I have a table named bcfsite with a field named activestate.
update bcfsite set activestate = 1 where bscname like '%B361Z%'
When I run the above query SQLPlus or Oracle SQL Developer, it works fine without any problems, but when I run it in Java using this code:
String sqlstrString = "update bcfsite
set activestate = 0 where bscname like '%B361Z%' ";
PreparedStatement ps = d.prepareStatement(sqlstrString);
ResultSet rs = ps.executeUpdate();
or this code :
ResultSet rs = DBConnection.RunStatement(sqlstrString, d);
My program pends and doesn't pass the update statement.
I changed the table and column and tried delete instead of update but still I see the same problem.
I am putting this is the answer box because there is not enough room in the comments...
String qString = "update bcfsite set activestate = 0 where bscname like ?";
That is the correct way to do this with a replaceable parameter. Remember when using the like operator everything passed to it is a varchar2 as far as oracle is concerned so:
ps.setString(1,"%B361Z%");
Again, this is the correct way to accomplish this.
The resulting string passed to oracle via jdbc will look like:
update bcfsite set activestate = 0 where bscname like '%B361Z%'
setString() applies the correct markup so the oracle query parser will see a correct query.
Queries with a "?" in them are not simply string replaced. The statement is parsed by the server, and then the parameter(s) are passed to the server.
BTW this was answered in several places on SO. Please learn how to search SO and it will shorten your response time considerably and not waste our time.
Can you try following approach first to clear out it updates atleast one row through Java code, don't give wild characters try to update single row.
String sqlstrString = "update bcfsite
set activestate = 0 where bscname=?";
PreparedStatement ps = d.prepareStatement(sqlstrString);
ps.setString(1, "B361Z");
ResultSet rs = ps.executeUpdate();
This may rule out other issues like connectivity/different schema ..
Please post the result.
Try this approach:
String sqlstrString = "update bcfsite " +
"set activestate = 0 where bscname like '?'";
PreparedStatement ps = d.prepareStatement(sqlstrString);
ps.setString(1, "%"+"B361Z"+"%");
ResultSet rs = ps.executeUpdate();
And a second approach would be:
...set activestate=0 where bscname like CONCAT('%', ?, '%')";
...
ps.setString(1, "B361Z");
Related
I am creating a new register in table MY_TABLE using java and then, I am doing a query to obtain the max(id) of that table. However, Java is obtaining the previous one. I mean:
mybean.store(con)
con.commit();
pstm = con.prepareStatement("SELECT MAX (ID) FROM MY_TABLE");
rs = pstm.executeQuery();
while (rs.next()){
id = rs.getString("ID");
System.out.println("id: " +id);
}
Before con.commit(); the table has the max(ID)=3
After com.commit() the table has the max(ID)=4
But I obtain MAX(ID)=3
Can somebody help me to solve this?
You're doing it; if this is returning the wrong result either your DB doesn't contain what you think it contains, or your DB engine is broken (MySQL is often broken, possibly that's the problem. The fix is to not use mysql), or your code is broken. Your snippet contains an error (no semicolon after the first line), so this isn't a straight paste but a modification; generally you should paste precisely the code that is exhibiting the behaviour you don't understand, because if you edit it or try to simplify it without running the simplification, you may have accidentally removed the very thing that would explain what you're observing.
More generally, if all you want is the ID generated for an auto-increment column, this isn't how you do it. You can use statement's .getGeneratedKeys() method to get at these; you may have to pass in Statement.RETURN_GENERATED_KEYS as part of your executeUpdate call.
You do not need a PreparedStatement if you do not have a parametrized query. I would use Statement in this case.
You do not need while (rs.next()) as your query will return a single value. I would use if (rs.next()).
Your query does not have a field called ID and therefore rs.getString("ID") will throw SQLException. You should use rs.getString(1) or use an alias (e.g. maxId in the example shown below) in the query. Also, you should use getInt instead of getString.
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT MAX(ID) AS maxId FROM MY_TABLE");
int id = Integer.MIN_VALUE;
if (rs.next()) {
id = rs.getInt(1);
//id = rs.getInt("maxId");
}
System.out.println(id);
This question already has answers here:
Java PreparedStatement complaining about SQL syntax on execute()
(6 answers)
Closed 6 years ago.
This is a really weird error that only started appearing today. When I use a prepared statement with ? for parameters, I get an error, but when I use it without parameters, it works just fine.
Here is the error-causing code:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM ?");
prep.setString(1, table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This produces the following error:
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''files'' at line 1
Also, changing it to the following works just fine:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM " + table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This doesn't seem to be making a whole lot of sense. Any ideas?
Tried it on another table and got more weired results.
This works and logs the admin in correctly:
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE " + column + " = '" + hashedPassword + "'";
PreparedStatement prepared = connection.prepareStatement(sql);
The following doesn't cause errors, but returns a message saying that the password entered is incorrect (it's correct - I double triple checked).
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE ? = ?";
PreparedStatement prepared = connection.prepareStatement(sql);
prepared.setString(1, column);
prepared.setString(2, hashedPassword);
Got it: use ? for values.
Also, the answer here helped.
Bind parameters cannot be used for identifiers in the SQL statement. Only values can supplied through bind placeholders.
This will work:
SELECT foo FROM bar WHERE id = ?
This will not work, because the table name is an identifier
SELECT foo FROM ? WHERE id = 2
You can't supply a column name, because column names are also identifiers.
A statement like this will run, but it may not do what you think it does.
SELECT ? AS foo FROM bar WHERE ? = 0
If we supply values of 'foo' for both placeholders, the query will actually be equivalent to a query containing two string literals:
SELECT 'foo' AS foo FROM bar WHERE 'foo' = 0
MySQL will run that statement, because it's a valid statement (if the table bar exists and we have privileges on it.) That query will return every row in bar (because the predicate in the WHERE clause evaluates to TRUE, independent of the contents of the table.. And we get returned the constant string foo.
It doesn't matter one whit that the string foo happens to match the name of column in our table.
This restriction has to do with how the SQL optimizer operates. We don't need to delve into all the details of the steps (briefly: parsing tokens, performing syntax check, performing semantics check, determining query plan, and then the actual execution of the query plan.)
So here's the short story: The values for bind parameters are supplied too late in that process. They are not supplied until that final step, the execution of the query plan.
The optimizer needs to know which tables and columns are being referenced at earlier stages... for the semantics check, and for developing a query plan. The tables and columns have to be identified to the optimizer. Bind placeholders are "unknowns" at the time the table names and column names are needed.
(That short story isn't entirely accurate; don't take all of that as gospel. But it does explain the reason that bind parameters can't be used for identifiers, like table names and column names.)
tl;dr
Given the particular statement you're running, the only value that can be passed in as a bind parameter would be the "hashedPassword" value. Everything else in that statement has to be in the SQL string.
For example, something like this would work:
String sqltext = "SELECT * FROM mytable WHERE mycolumn = ?";
PreparedStatement prepared = connection.prepareStatement(sqltext);
prepared.setString(1, hashedPassword);
To make other parts of the SQL statement "dynamic" (like the table name and column name) you'd have to handle that in the Java code (using string concatenation.) The contents of that string would need to end up like the contents of the sqltext string (in my example) when it's passed to the prepareStatement method.
The parameters of PreparedStatement should be applied only in parameters that can be used in conditional clauses. The table name is not the case here.
If you have a select where the table name can be applied in the conditional clause you can do it, otherwise you can not.
I have a table in a MySQL database which is 2 columns,
String insertquery = "INSERT INTO Table (Col1, Col2) VALUES (?, ?)";
PreparedStatement preparedStatement = dbConnection.prepareStatement(insertSQL);
preparedStatement.setString(1, "Val 1");
preparedStatement.setString(2, "Val 2");
preparedStatement.executeUpdate();
The thing is that the second column values decide at run time, where to insert value or keep default.
how to set setString as default .
preparedStatement.setString(2, default );
or can i write two seperate sql depends upon condition ? is there any way to handle this senario?
same issue for update sql.
String updatequery = "UPDATE Table SET Col1=?, Col2=?;"
PreparedStatement preparedStatement = dbConnection.prepareStatement(updatequery);
preparedStatement.setString(1, "Val 1");
preparedStatement.setString(2, "Val 2");
preparedStatement.executeUpdate();
I am able to set like this
preparedStatement.setNull(2, '');
I have to kept old value as it is, not update as null
Thank you...
To achieve this, you have to leave out the column name and MySQL will then use the default value for any column names that have been omitted.
So when you want the value of Col2 to be the default, then you would write your query like so:
"INSERT INTO Table (Col1) VALUES (?)";
I think your best choice is to actually prepare the statement itself at run-time based on the columns that you want to change.
I'm not really sure how easily this can be done in Java but with PHP this could be done so easily by having an array of column names and adding/removing items off the array at run-time depending on what columns needs to be updated and then using the PHP Implode function to glue each item of the array with a comma and finally concatenating the resulting string to your final query.
Maybe you might be able to find solutions that are more suited for java by reading through this related stack-overflow answer.
Good luck
I have a java servlet application and I'm using a prepared query to update a record in a SQL Server Database table.
Lets say I want to execute UPDATE MyTable SET name = 'test' WHERE id = '10'. (Yes, id is a varchar)
I used the following code to make this happen:
PreparedStatement pstmt = con.prepareStatement("UPDATE MyTable SET name = ? WHERE id = ?");
pstmt.setString(1, getName() );
pstmt.setString(2, getID() );
pstmt.executeUpdate();
I found out that while I was running a JMeter script to simulate 2 users, this statement causes a deadlock in my database.
I wanted to check what my values were in the SQL Profiler so I used the following code, so I could check the values.
String query = String.format("UPDATE MyTable SET name = '%s' WHERE id = '%s' ", getName(), getID() );
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.executeUpdate();
Suddenly my deadlock was gone! It's a shame the last approach is vulnerable to SQL injection.
Is there somebody who can tell me what is going on and/or how to fix it?
Ok I finally found the problem and solution to my problem.
It seemed that the combination of the jTDS JDBC driver with MSSQL was the 'problem'.
This article explained my situation exactly. And with the help of this FAQ I was able to set the datasource to the right configuration.
From what I understand:
If you have statement that uses a String-like index (Like in my situation), the table performs an index SCAN instead of an index SEEK. This causes the whole table to be locked and vulnerable to deadlocks.
I hope this will help other people too.
The query code and query:
ps = conn.prepareStatement("select instance_id, ? from eam_measurement where resource_id in (select RESOURCE_ID from eam_res_grp_res_map where resource_group_id = ?) and DSN like '?' order by 2");
ps.setString(1,"SUBSTR(DSN,27,16)");
ps.setInt(2,defaultWasGroup);
ps.setString(3,"%Module=jvmRuntimeModule:freeMemory%");
rs = ps.executeQuery();
while (rs.next()) { bla blah blah blah ...
Returns an empty ResultSet.
Through basic debugging I have found its the third bind that is the problem i.e.
DSN like '?'
I have tried all kinds of variations, the most sensible of which seemed to be using:
DSN like concat('%',?,'%')
but that does not work as I am missing the ' on either side of the concatenated string so I try:
DSN like ' concat('%',Module=P_STAG_JDBC01:poolSize,'%') ' order by 2
but I just cannot seem to find a way to get them in that works.
What am I missing?
First, the PreparedStatement placeholders (those ? things) are for column values only, not for table names, column names, SQL functions/clauses, etcetera. Better use String#format() instead. Second, you should not quote the placeholders like '?', it would only malform the final query. The PreparedStatement setters already do the quoting (and escaping) job for you.
Here's the fixed SQL:
private static final String SQL = "select instance_id, %s from eam_measurement"
+ " where resource_id in (select RESOURCE_ID from eam_res_grp_res_map where"
+ " resource_group_id = ?) and DSN like ? order by 2");
Here is how to use it:
String sql = String.format(SQL, "SUBSTR(DSN,27,16)"); // This replaces the %s.
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, defaultWasGroup);
preparedStatement.setString(2, "%Module=jvmRuntimeModule:freeMemory%");
See also:
Sun JDBC tutorial: Using Prepared Statements
Format string syntax
If you want to use LIKE in prepared statement and also want to use % characters in LIKE;
write prepared statement as normally " .... LIKE ? ...." and while assigning parameter value to question mark use
ps.setString(1, "%" + "your string value" + "%");
This will work :)
There are two problems with your statement. You have to understand how bind variables work. The query is not processed by substituing the characters ? with your parameters. Instead, the statement is compiled with placeholders and then, during execution, the actual values of the parameters are given to the DB.
In other words, you parse the following query:
SELECT instance_id, :p1
FROM eam_measurement
WHERE resource_id IN (SELECT RESOURCE_ID
FROM eam_res_grp_res_map
WHERE resource_group_id = :p2)
AND DSN LIKE '?'
ORDER BY 2
I'm pretty sure the last parameter will be ignored because it is in a delimited character string. Even if it is not ignored, it does not make sense to have ' characters around because Oracle won't bind a parameter in a string (I'm surprised it hasn't raised any error, do you catch exceptions ?).
Now if you replace your DNS LIKE '?' with DSN LIKE ? and bind "%Module=jvmRuntimeModule:freeMemory%" this will make sense and should return the correct rows.
You still have the problem with your first parameter, it won't do what you expect, i-e the query that will be executed will be equivalent to the following query:
SELECT instance_id, 'SUBSTR(DSN,27,16)'
FROM ...
which is not at all the same as
SELECT instance_id, SUBSTR(DSN,27,16)
FROM ...
I would suggest parsing (=prepareStatement) the following query if you expect the SUBSTR to be dynamic:
SELECT instance_id, SUBSTR(DSN,?,?)
FROM eam_measurement
WHERE resource_id IN (SELECT RESOURCE_ID
FROM eam_res_grp_res_map
WHERE resource_group_id = ?)
AND DSN LIKE ?
ORDER BY 2
Omit the ' around the ?. Without the ', ? is a placeholder for a parameter. With it, it's an SQL string (i.e. the same as "?" in Java).
Then you must concatenate the string on the Java side; you can't pass SQL functions as parameters to queries; only basic values (like string, integer, etc) because the JDBC driver will convert the parameter to the SQL type the database expects and it cannot execute SQL functions in this step.
You can try:
String beforeAndAfter = "%" + yourVariable + "%";
PreparedStatement ps = con.prepareStatement(
"select columname from tablename where LOWER(columnname) LIKE LOWER('"+var+"%')");
Here var is the variable in which value that is to be searched is stored...
This should work:
"\'" + "?" + "\'"