setXXX methods of PreparedStatement not working - java

I got something like this.
PreparedStatement statement = manager.getConnection().prepareStatement("delete from student_marks where reg_number = ? and semester = ?");
statement.setInt(1,1);
statement.setString(2,"S1");
System.out.println(statement.executeUpdate());
But the executeUpdate is returning 0 when I do this. If I directly replace the '?' with the values, then executeUpdate is woriking properly. In my case, it returned 4 meaning that 4 rows were deleted. I am not able to understand where the problem lies.

It depends on your column type... If column type for reg_number is number(any numeric data type), then only you must set it integer, else otherwise you must set it using string.
PreparedStatement statement = manager.getConnection().prepareStatement("delete from student_marks where reg_number = ? and semester = ?");
statement.setString(1,"1");
statement.setString(2,"S1");
System.out.println(statement.executeUpdate());
As jlordo pointed out, Did you reinsert the records before deleting it next time?

Related

Use Value If Exists Else Use Default Value MySQL

Current Tools: Using Java to communicate with MySQL
I tried doing a search multiple times and ended up with this, but it didn't help me solve my problem. Google Search
I'm currently writing some query statements to try to save some information about my game objects to a database. I wanted to save the object's ID number if it wasn't 0, and to use the auto increment function otherwise if it was 0. For an example:
// (?,?) = (itemid, amount)
// itemid -> primary key and auto increment.
PreparedStatement ps = db.prepareStatement("INSERT INTO items (?,?)");
ps.setInt(1, item.id() == 0 ? >>>>DEFAULT<<<< : item.id());
ps.setInt(2, item.quantity());
The issue of course is that the way I'm doing isn't the correct way to tell MySQL to auto increment instead. Is there a way to do so? Also, the reason why I'm purposely inserting an ID in even though it's auto-increment is that I wrote a method previously that allowed me to save the original state of an item (thus preserving its stats). Upon loading this item, I want to be able to replace the current item and its stats with the newly loaded one.
Main Problem: Want to be able to insert a value if a condition is satisfied, otherwise use the auto-increment for primary key if possible. If there is something wrong with my approach, I'm open ears. Currently a beginner at databases!
EDIT:
As per MySQL suggestion, if you insert 0 into the id column, that column will automatically generate a sequence number.
Here: http://dev.mysql.com/doc/refman/5.7/en/example-auto-increment.html
Note that you should set the column (id) to AUTO-INCREMENT when the table is created. The auto increment will start at 1 so I you insert 0 the next max number will be inserted.
PreparedStatement ps = db.prepareStatement("INSERT INTO item(id, quantity) VALUES(?,?)");
ps.setInt(1, item.id());
ps.setInt(2, item.quantity());
Try it
PreparedStatement ps = db.prepareStatement("INSERT INTO items (?,?)");
ps.setInt(1, (item.id() == 0 ? 0 : item.id()));
ps.setInt(2, item.quantity());

Java MySql preparedStatement

Hey I have problem with preparedStatement, I want to find min for few columns, I'm iterating over the names of columns and inserting them inside my preparedStatement like that
connection.prepareStatement("SELECT min( ? ) as min FROM test");
minStatement.setString(1, "some_column");
and when retrieving from ResultSet I'm getting the column name, in this case the result is "some_column" and should be 0. When using normal statement it does return right value.
I have no idea what I'm doing wrong.
Thanks for any help.
You cannot specify a column name in prepared statement like this, what you get is:
SELECT MIN('some_column') AS min FROM test
Instead of:
SELECT MIN(some_column) AS min FROM test
So, your query selects the minimal value 'some_column'... which is 'some_column'.
You could, instead, try that:
connection.prepareStatement("SELECT min(" + some_column + " ) as min FROM test");
But this may lead to injection attacks.

PreparedStatement multiple replacements without a comma separator

I have the following PreparedStatement:
PreparedStatement statement = conn.prepareStatement("Select * from foo
where foo.age ? ? AND foo.children ? ?")
Now to explain what I am looking to do, because I am lazy and don't like writing multiple queries. I want the statement to look like the following when finished:
Select * from foo where foo.age >= 42 AND foo.children <= 3
OR
Select * from foo where foo.age = 42 AND foo.children = 3
If it isn't clear I want to be able to substitute multiple tokens in a row, where the first token happens to be a qualifier (equals,greater,less,etc) and the token following it happens to be a literal (3,17,"Steve",etc). My question is is this possible and if so how can this be accomplished?
You can't do this, because ? doesn't represent a token, but rather a value. Obviously some tokens (namely literals) represent values, but even for these, the ? directly represents the value itself, not the literal-that-also-represents-the-value. (This is an intentional element of the design, because the very purpose of parameterized queries is to prevent parameters from "leaking out" and being interpreted as something other than single values.)
Edited to add: Where I work, we have a custom framework that wraps around JDBC and handles transactions and so on, so we don't usually have to deal with PreparedStatement directly. That framework has a method that looks something like this:
public <T> Iterator<T> executeQuery(ConverterFromResultSetToT<T> converter,
String query, Map<String, Object> params)
{
// . . . modify query, replacing any instances of $!{paramKey} with the
// corresponding value from params -- this allows arbitrary SQL code
// to be injected, in the rare cases that that's necessary
// . . . modify query, replacing any instances of ${paramKey} with '?' and
// adding the corresponding value from params to an array -- we use
// this much more often
// . . . create PreparedStatement with the resulting query
// . . . set parameters of PreparedStatement from aforemented array
// . . . run PreparedStatement; wrap result in an Iterator<T>; and return
}
But I'd only recommend that sort of thing if you expect to be doing a lot of this. We put a lot of effort into that framework, and it's incredibly useful, but it's also a lot of code.
It's worth noting that, despite what the documentation might imply, the cost of creating a PreparedStatement is not very high. Unless you're really running the same query a large number of times, it's not a big deal if you re-create the PreparedStatement each time. So you don't really need built-in support for drop-in operators, as long as you're willing to write your own code for that.
This cannot be done. The parameters in a PreparedSatement can only be values, not operators, table names and such like.
Now, for the specific queries above you can do the following:
select * from foo where age > ? and age < ?
Then with 42, 400 you get age>=42 years and with 42, 42 you get age = 42
You can have a workaround as :
String query = "Select * from foo where foo.age # # AND foo.children # #";
//write code here to manipulate your query string using
query = query.replaceFirst("#", "=");
query = query.replaceFirst("#", "42");
query = query.replaceFirst("#", "=");
query = query.replaceFirst("#", "3");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query );
If you decide to use replaceFirst as above, please be aware that you are assigning the value from left to right.
String firstOperator = ">="
String secondOperator = "<="
PreparedStatement statement = conn.prepareStatement("Select * from foo
where foo.age "+firstOperator+" ? AND foo.children "+secondOperator+" ?");
statement.setInt(1,42);
statement.setInt(2,3);
Anyway I don't think it's a very elegant thing to do. "Not writing multiple queries" doesn't seem to be a sensible design goal.

Prepared statement with wildcard not returning certain rows but query returns all rows?

I'm using JTDS as a driver to connect to SQL server.
Here's the query that's giving me problems:
SELECT EmpID,FirstName,LastName,CompanyName,DepartmentName,JobTitle,HireDate FROM Employees where UPPER(FirstName) LIKE 'KEVIN%'
It returns 2 rows on SQL Server. One that has 'KEVIN' in upper case and another that has 'Kevin' like so. I used the wildcard to make sure I get both results. In my EmployeeDAO class I'm using the following:
ps = con.prepareStatement("SELECT EmpID,FirstName,LastName,CompanyName,"
+ "DepartmentName,JobTitle,HireDate FROM Employees WHERE UPPER(FirstName) LIKE ?");
ps.setString(1, FirstName + "%");
rs = ps.executeQuery();
And then of course I put KEVIN on my main. It only returns ONE row, which is the 'Kevin' row.
How do I fix this so it returns all rows?
Your query looks fine (although I would uppercase the parameter value before setting it, to make it more robust). The problem is just in the way how you're collecting the rows from the ResultSet. Likely you're plain overriding the previous row with the next row so that you end up with only one row (the last one) in your collection.
Default collation of the SQL Server installation is SQL_Latin1_General_CP1_CI_AS and it is not case sensitive.
Change collation of the query:
SELECT Col1
FROM Table1
WHERE Col1 COLLATE Latin1_General_CS_AS LIKE 'KEVIN%'

Query does not work with a parameter marker with preparedStatement

Excerpt from code
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM sch.tab1 where col1 like lower ( 'ABZ' ) ");
preparedStatement.executeQuery();
The above code executes successfully.
But when i try to execute this
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM sch.tab1 where col1 like lower ( ? ) ");
preparedStatement.setString ( myValue );
preparedStatement.executeQuery();
It throws an exception."STRING TO BE PREPARED CONTAINS INVALID USE OF PARAMETER MARKERS"
What could be the problem here?
Answer found, see the comments
I suspect the problem is that you can't apply functions directly to parameters. Is there any particular reason why you want the lower casing to be performed at the database rather than in your code? (I can think of some potential reasons, admittedly.) Unless you really need to do this, I'd just change the SQL to:
SELECT * FROM sch.tab1 where col1 like ?
and call toLower() in Java, preferably specifying the appropriate locale in which to perform the lower-casing.
I think Carlos is on to something. Try
SELECT * FROM sch.tab1 where col1 like lower ( '' + ? )
or whatever passes for string concatenation operator in your version of SQL. Forcing a string context might get you past the error. May require extra parentheses.
For reference: I ran into the same problem while using the NORMALIZE_STRING function:
SELECT NORMALIZE_STRING(?, NFKD) FROM sysibm.sysdummy1
Error message:
THE DATA TYPE, LENGTH, OR VALUE OF ARGUMENT 1 OF NORMALIZE_STRING IS INVALID. SQLCODE=-171, SQLSTATE=42815, DRIVER=4.13.111
Using the following statement solved the problem (CONCAT). Thanks to Paul Chernoch!
SELECT search_normalize(NORMALIZE_STRING(? CONCAT G'', NFKD)) FROM sysibm.sysdummy1
Note the "G" prefix for Unicode compatibility.

Categories