I am having some problems and I'm sure it's something stupid.
So I have a query like
SELECT name, id, xyz FROM table ORDER BY ?
then later down the road setting the ? doing a
ps.setString(1, "xyz");
I am outputting the query and the value of xyz in the console. When I loop through the ResultSet returned from the PreparedStatement the values are not in the correct order. They are in the returned order as if I had left the ORDER BY clause off. When I copy/paste the query and the value into TOAD it runs and comes back correctly.
Any ideas to why the ResultSet is not coming back in the correct order?
The database will see the query as
SELECT name, id, xyz FROM table ORDER BY 'xyz'
That is to say, order by a constant expression (the string 'xyz' in this case). Any order will satisfy that.
? is for parameters, you can't use it to insert column names. The generated statements will look something like
SELECT name, id, xyz FROM table ORDER BY 'xyz'
so that your entries are sorted by the string 'xyz', not by the content of column xyz.
Why not run:
ps.setInteger(1, 3);
Regards.
EDIT: AFAIK Oracle 10g supports it.
PreparedStatement placeholders are not intend for tablenames nor columnnames. They are only intented for actual column values.
You can however use String#format() for this, that's also the way I often do. For example:
private static final String SQL_SELECT_ORDER = "SELECT name, id, xyz FROM table ORDER BY %s";
...
public List<Data> list(boolean ascending) {
String order = ascending ? "ASC" : "DESC";
String sql = String.format(SQL_SELECT_ORDER, order);
...
Another example:
private static final String SQL_SELECT_IN = "SELECT name, id, xyz FROM table WHERE id IN (%s)";
...
public List<Data> list(Set<Long> ids) {
String placeHolders = generatePlaceHolders(ids.size()); // Should return "?,?,?..."
String sql = String.format(SQL_SELECT_IN, placeHolders);
...
DAOUtil.setValues(preparedStatement, ids.toArray());
...
The database will see the query like this
SELECT name, id, xyz FROM table ORDER BY 'xyz'
I think you should add more variable like order_field and order_direction
I assume you have a method like below and I give you an example to solve it
pulbic List<Object> getAllTableWithOrder(String order_field, String order_direction) {
String sql = "select * from table order by ? ?";
//add connection here
PreparedStatement ps = (PreparedStatement) conn.prepareStatement(sql);
ps.setString(1,order_field);
ps.setString(2,order_direction);
logger.info(String.valueOf(ps)); //returns something like: com.mysql.jdbc.JDBC4PreparedStatement#a0ff86: select * from table order by 'id' 'desc'
String sqlb = String.valueOf(ps);
String sqlc = sqlb.replace("'"+order_field+"'", order_field);
String sqld = sqlc.replace("'"+order_direction+"'", order_direction);
String[] normQuery = sqld.split(":");
ResultSet result = conn.createStatement().executeQuery(normQuery[1]);
while(result.next()) {
//iteration
}
}
Related
Here i made table called sub_master with column sub_id and name, insertion and deletion working perfectly fine with this, so put those functions here as well to get reference for update function
and i'm using PostgreSQL for this.
In command line UPDATE query is working fine and query as:
UPDATE school_submaster SET name ='' WHERE sub_id = ;
private void InsertRowActionPerformed(java.awt.event.ActionEvent evt)
{
String query = "INSERT INTO school_submaster (sub_id, \"name\") VALUES ("+SidInput.getText()+",'"+SnameInput.getText()+"')";
executeSQlQuery(query, "Inserted");
}
private void UpdateRowActionPerformed(java.awt.event.ActionEvent evt)
{
String query = "UPDATE school_submaster SET 'name' ='"+SnameInput.getText()+"'+WHERE sub_id = "+SidInput.getText();
executeSQlQuery(query, "Updated");
}
private void DeleteRowActionPerformed(java.awt.event.ActionEvent evt)
{
String query = "DELETE FROM school_submaster WHERE sub_id = "+SidInput.getText();
executeSQlQuery(query, "Deleted");
}
Only use single quotes for string and date constants. Never use single quotes around column names or table names.
Your update is:
UPDATE school_submaster
SET 'name' ='<something>'+WHERE sub_id = "+SidInput.getText();
This has the additional issue of a + in the query string. It should look ore like:
UPDATE school_submaster
SET name = '<something>'
WHERE sub_id = "+SidInput.getText();
But even that is not true. You need to learn to use parameters to pass parameters into queries. The query should be some variant of:
UPDATE school_submaster
SET name = ?
WHERE sub_id = ?
Where the ? is a placeholder for a parameter (it might also be #name or something else).
You are missing a space in the sql WHERE clause, so add it as shown below:
String query = "UPDATE school_submaster SET 'name' ='"+
SnameInput.getText()+"' WHERE sub_id = "+SidInput.getText();
Following is my code(Re-constructed) which select & update STATUS field depending upon the conditions. (Using Servlets, Oracle as Backend and JDBC driver)
ResultSet rs=null;
String query = "select A.NAME, A.ADDRESS, A.STATUS, B.CLASS from TABLE_ONE A, TABLE_TWO B where A.STATUS='N'";
pstmt = con.prepareStatement(query,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
rs = pstmt.executeQuery();
while(rs.next())
{
String name = rs.getString("NAME");
String address = rs.getString("ADDRESS");
String class = rs.getString("CLASS");
String msg = //Other statements to check what status to be set
if(msg.equals("OK"))
rs.updateString("STATUS", "S");
else
rs.updateString("STATUS", "E");
rs.updateRow();
}
I am getting the error while updating:
java.sql.SQLException: Invalid operation for read only resultset: updateString
Any suggestions will be appreciated.
Update 1:
The same code was working when select statement was selecting data from single table, so is there any issue when selecting data from two tables in single query?
[Note: As #javaBeginner has mentioned in comments it will work only for one table.]
The following limitations are placed on queries for enhanced result sets. Failure to follow these guidelines will result in the JDBC driver choosing an alternative result set type or concurrency type.
To produce an updatable result set (from specification):
A query can select from only a single table and cannot contain any join operations.
In addition, for inserts to be feasible, the query must select all non-nullable columns and all columns that do not have a default value.
* A query cannot use "SELECT * ". (But see the workaround below.)
* A query must select table columns only. It cannot select derived columns or aggregates such as the SUM or MAX of a set of columns.
To produce a scroll-sensitive result set:
A query cannot use "SELECT * ". (But see the workaround below.)
A query can select from only a single table.
Try This :
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
//Execute a query
String sql = "select A.NAME, A.ADDRESS, A.STATUS, B.CLASS from TABLE_ONE A, TABLE_TWO B where A.STATUS='N'";
ResultSet rs = stmt.executeQuery(sql);
//Extract data from result set
rs.beforeFirst();
while(rs.next())
{
String name = rs.getString("NAME");
String address = rs.getString("ADDRESS");
String class = rs.getString("CLASS");
String msg = //Other statements to check what status to be set
if(msg.equals("OK"))
rs.updateString("STATUS", "S");
else
rs.updateString("STATUS", "E");
rs.updateRow();
}
Just changed Prepared statement to create statement
SELECT * makes the resultSet readonly. SELECT COLUMN_NAME makes it updatable.
So instead of SELECT * FROM TABLE use SELECT COLUMN1, COLUMN2, ... FROM TABLE.
I am new to mysql and I am trying to connect to the database using a Java Program and I am passing a mysql query.
public class dbconnect {
public static void main(String[] args) throws SQLException,ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase?user=root&password=root");
Statement st = conn.createStatement();
int custid= 0;
String myname = null;
String query = "select name from groups where customer_id = 2;";
//This query has a problem can anyone help me fix it.
System.out.println(query);
ResultSet rs1 = st.executeQuery(query);
System.out.println("after query");
while (rs1.next()){
custid = rs1.getInt("customer_id");
myname = rs1.getString("name");
System.out.println(myname);
System.out.println(custid);
}
}
}
I am passing a query "select name from groups where customer_id = 2" .
Here "name" is a coloumn,"groups" is a table and "customer_id" is another column. In the program when I give this query(no typos) I get the following error
Exception in thread "main" java.sql.SQLException: Column 'customer_id' not found.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1144)
at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2815)
at com.memoir.client.widgets.memogen.dbconnect.main(dbconnect.java:61)
I have checked with the table , customer_id is present in the table . They are no spelling mistakes also .Even then it says that customer_id column is not found .
Can anyone help me fix it.
The query needs to be:
String query = "select name, customer_id from groups where customer_id = 2;";
Honestly it doesn't make any sense, your query is
String query = "select name from groups where customer_id = 2;";
and you expect to get customer_id ??
as you are already passing customer_id in where clause you don't need to get it back again from db.
String query = "select customer_id,name from groups where customer_id = 2;";
The above would work with your current code .
You are accessing only name column in query and you are try to get "customer_id" in while loop from result set
while (rs1.next()){
custid = rs1.getInt("customer_id"); // **error is here - remove this line or change your query**
myname = rs1.getString("name");
System.out.println(myname);
System.out.println(custid);
}
Your problem is that you are trying to get an invalid column ("cutomer_id") from the result set which contains only the "name" column.
To resolve this you have to select also the "customer_id" in your query:
"select name, customer_id from groups where customer_id = 2";
custid = rs1.getInt("customer_id");
you result set does not have customer_id
Include that too in your query
try this
String mysqlquery = "select name, customer_id from groups where customer_id=2";
To avoid SQL injection attacks in my project, I'm attempting access database with Parameterized Query way. Right now I know how to handle equal case like below (With Spring JdbcTemplate):
String sql = "SELECT * FROM T_USER WHERE USERNAME = ? AND PASSWORD = ?"
jdbcTemplate.query(sql,
new UserRowMapper(),
new Object[]{"%admin%", "%password%"});
Above code runs no problem, but I had no idea how to handle the 'IN' case, following is my case, and it works failed:
String sql =
"SELECT * FROM T_USER WHERE USERNAME = ? AND PASSWORD = ? AND CLASS_ID IN (?)"
jdbcTemplate.query(sql,
new UserRowMapper(),
new Object[]{"%admin%", "%password%", "1,2,3"});
Anybody give me guidance? Thanks a lot.
I think you can create a List and pass it as 3rd parameter. Also You need to use LIKE in place of = in first two column filters.
List<Integer> classIds = new ArrayList<Integer>();
classIds.add(1);
classIds.add(2);
classIds.add(3);
String sql = "SELECT * FROM T_USER WHERE "+
"USERNAME LIKE ? AND PASSWORD LIKE ? AND CLASS_ID IN (?)";
jdbcTemplate.query(sql, new Object[]{"%admin%", "%password%", classIds},
new UserRowMapper());
Please note: Here is the syntax:
public List query(String sql, Object[] args, RowMapper rowMapper)
throws DataAccessException
EDIT: Please try namedParameterJdbcTemplate as bwlow:
String sql = "SELECT * FROM T_USER WHERE "+
"USERNAME LIKE :uname AND PASSWORD LIKE :passwd AND CLASS_ID IN (:ids)";
Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("uname", "%admin%);
namedParameters.put("passwd", "%password%");
namedParameters.put("ids", classIds);
List result = namedParameterJdbcTemplate.query(sql, namedParameters,
new UserRowMapper());
Three options:
Generate different JDBC queries for each length of the IN LIST, and parameterize each INDIVIDUAL item, e.g. this answer
For small tables, you can cheat and use a LIKE statement, e.g. this answer
Use a SPLIT function (anti-LISTAGG) to turn the delimited list into individual rows of one column each, and JOIN against it. Example SPLIT function
You'll parameterize the argument to the function as a single string
I have this piece of code, with a prepared statement. I know the query is redundant. the parameter id is a string <space>413530 (" 413530"). Please note the preceding whitespace character.
String query = "SELECT RSCode as id FROM Customer WHERE RSCode=?";
PreparedStatement newPrepStatement = connection
.prepareStatement(query);
newPrepStatement.setString(1, id);
resultSet1 = newPrepStatement.executeQuery();
while (resultSet1.next()) {
System.out.println("Got a result set.");
logindata.add(resultSet1.getString("id"));
}
I do not get any results after executing this query.
Now, if I use the same statements and append the parameter as part of the string as follows:
String query = "SELECT RSCode as id FROM Customer WHERE RSCode=" + id;
PreparedStatement newPrepStatement = connection
.prepareStatement(query);
resultSet1 = newPrepStatement.executeQuery();
while (resultSet1.next()) {
System.out.println("Got a result set.");
logindata.add(resultSet1.getString("id"));
}
I get a result as after executing this prepared statement. Same also works with a java.sql.statement
I wish to know why the driver ignores the whitespace in the second piece of code, but has a problem in the first part.
If you use setString the parameter will be bound as a string resulting in this SQL (considering the bound parameter an SQL string):
SELECT RSCode as id FROM Customer WHERE RSCode=' 0123';
If you use concatenation the SQL used will be (considering the concatenated value as an integer, since space will be ignored as part of the SQL syntax):
SELECT RSCode as id FROM Customer WHERE RSCode=<space>0123;
In this case I would advise to convert it to int or long or whatever it is and bind it with the right type. With setInt() or setLong().
And if you field is a string you could normalize it first using for example:
String normalizedValue = String.trim(value);
newPrepStatement.setString(1, normalizedValue);
or even direct in SQL like:
SELECT RSCode as id FROM Customer WHERE RSCode=TRIM(?);
In scenario - 1, the query will look like this
"SELECT RSCode as id FROM Customer WHERE RSCode=' 413530'"
In scenario - 2, the query will look like this
"SELECT RSCode as id FROM Customer WHERE RSCode= 413530"