Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
public class StudentDAO extends ConnectorDAO {
private List<StudentBean> studentList = new LinkedList<>();
private StudentBean studentBean;
public List<StudentBean> retrieveStudents() {
Connection connection;
try {
String myQuery = "SELECT ?, ?, ? FROM Students";
connection = getConnection() // getConnection() comes from superclass
PreparedStatement preparedstatement = connection.prepareStatement(myQuery);
preparedStatement.setString(1, "firstname");
preparedStatement.setString(2, "lastname");
preparedStatement.setString(3, "studentID");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
studentBean = new StudentBean();
studentBean.setFirstName(resultSet.getString("firstname"));
studentBean.setLastName(resultSet.getString("lastname"));
studentBean.setID(resultSet.getInt("studentID"));
studentList.add(studentBean);
}
} catch (Exception e) {
// Error handling stuff
} finally {
// close connection, resultset and preparedstatement
}
}
}
An error shows in my eclipse. On the line where I set the studentBean's ID. The data type of the studentID in my database is of Int. I'm not sure how to retrieve it though. Can anyone help me? It works when I use a Statement object when I query with the parameters used in the prepared statement.
Your code for building the query is incorrect:
String myQuery = "SELECT ?, ?, ? FROM Students";
connection = getConnection() // getConnection() comes from superclass
PreparedStatement preparedstatement = connection.prepareStatement(myQuery);
preparedStatement.setString(1, "firstname");
preparedStatement.setString(2, "lastname");
preparedStatement.setString(3, "studentID");
Is not possible:
A query string is formatted like this (example):
String myQuery = "SELECT firstname, lastname, studentID FROM Students WHERE studentID=?";
The parameters are only to be used on variables not on column names, table names etc.
So once you have code like that you could query on a studentID (not your goal but just for the example):
preparedStatement.setInt(1, someStudentID);
Which would be send with the preparedStatement to the DBMS in which then the DBMS replaces the ? with the value of someStudentID.
The meaning of setString (or setInt or any other setXXX in PreparedStatement), is "replace the corresponding question mark with the given value, appropriately typed". So this code:
String myQuery = "SELECT ?, ?, ? FROM Students";
connection = getConnection() // getConnection() comes from superclass
PreparedStatement preparedstatement = connection.prepareStatement(myQuery);
preparedStatement.setString(1, "firstname");
preparedStatement.setString(2, "lastname");
preparedStatement.setString(3, "studentID");
Effectively creates the following query:
SELECT 'firstname', 'lastname', 'studentID' FROM Students
Now, this tells it to select three literal strings from the table. If you ran this query in an SQL command line utility or something similar, you'd find that the result is
firstname | lastname | studentID
firstname | lastname | studentID
firstname | lastname | studentID
firstname | lastname | studentID
...
Instead of what you expected. Anything set by setString is interpreted as a literal string - as if it includes single quotes.
So question marks are used for setting values in the statement, that would be literal values if you were typing the statement in a command line utility.
So what your result set has is rows upon rows containing the three strings firstname, lastname and studentID.
Now, in the next bit of code:
while (resultSet.next()) {
studentBean = new StudentBean();
studentBean.setFirstName(resultSet.getString("firstname"));
studentBean.setLastName(resultSet.getString("lastname"));
studentBean.setID(resultSet.getInt("studentID"));
studentList.add(studentBean);
}
in many database systems, you wouldn't even be able to use getString("firstname") because the returned column name from a query for literals is arbitrary. But I suppose your database system actually gives the return column the same name as the literal value. So you are able to retrieve firstname and lastname (But their content is not the student name! It's the literal strings "firstname" and "lastname"), because you are using getString.
But you run out of luck when you try to use getInt. Since you queried for literal strings, you are getting back three strings. The third column is not an integer but the literal string "studentID". This is where you hit the error.
So you should change your query to
"SELECT firstname, lastname, studentID FROM Students"
Which means you don't necessarily need a prepared statement in this case, but it doesn't hurt either.
Where can you use the question marks, then?
Anywhere you need a literal value in your query. For example, if you want to know the difference between a person's year of birth and a given year, you could write:
SELECT year_of_birth - ? FROM people
And then use setInt(1,1969) or setInt(1,2001) to make the query become:
SELECT year_of_birth - 1969 FROM people
and
SELECT year_of_birth - 2001 FROM people
Respectively. In prepared statements, the actual names of database objects such as columns and tables, which are not literals, cannot be replaced with a question mark. They are part of the query plan itself.
Related
When I try to sort by a value descending my SQL table does it correctly, but if it sees for example "1000" it always puts it in the middle?
for Example:
this even happens when I reference it in spigot (I'm using it for a plugin) it outputs it the same way
this is how I'm calling it in my plugin:
PreparedStatement statement = database.getConnection().prepareStatement("SELECT uuid FROM player_stats ORDER BY blocks_broken DESC");
ResultSet rs = statement.executeQuery();
while (rs.next()) {
String name = rs.getString("uuid");
LeaderboardCommand.name = name;
String player = String.valueOf(Bukkit.getPlayer(UUID.fromString(name)));
p.sendMessage(player);
I know it's not perfect as I'm just learning/experimenting with databases currently, but I'm mainly asking for help on why the SQL is outputted this way & advice on any severe mistakes I'm making is greatly appreciated!
Thanks in advance -Occy
public void createPlayerStats(PlayerStats playerStats) throws SQLException {
PreparedStatement statement = getConnection()
.prepareStatement("INSERT INTO player_stats(uuid, blocks_broken, last_login, last_logout) VALUES (?, ?, ?, ?)");
statement.setString(1, playerStats.getPlayerUUID());
statement.setLong(2, playerStats.getBlocksBroken());
statement.setDate(3, new Date(playerStats.getLastLogin().getTime()));
statement.setDate(4, new Date(playerStats.getLastLogout().getTime()));
statement.executeUpdate();
statement.close();
It happens because block_broken type is a varchar and not a number.
In this case you are ordering lexycographically and not numerically.
You can change your query to handle that as a numeric value with an explicit cast so your query should be:
SELECT uuid FROM player_stats ORDER BY cast(blocks_broken as numeric) DESC
Update: In MariaDb try to use this (You can try directly in the db client and once it is working update your java code):
SELECT uuid FROM player_stats ORDER BY CAST(blocks_broken AS INTEGER) DESC
This question already has an answer here:
ResultSet is not for INSERT query? Error message: Type mismatch: cannot convert from int to String
(1 answer)
Closed 5 years ago.
I am getting a error on the resultset rs part where netbeans shows the error as
incompatible types:int cannot be converted to resultset
Class.forName("java.sql.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql?useSSL=false", "root", "abc");
Statement stmt = conn.createStatement();
String query = "SELECT * FROM patient WHERE Mobile_No='" + mobno + "';"; /*Get the value from the database*/
ResultSet rs = stmt.executeUpdate(query);/*Part where the error is appearing*/
while (rs.next()) {
String Name = rs.getString("Name");
String Age = rs.getString("Age");
String Mobile = rs.getString("Mobile_No");
String gender = rs.getString("Gender");
String symptoms = rs.getString("Symptoms");
model.addRow(new Object[]{Name, Age, Mobile, gender, symptoms});
}
rs.close();
stmt.close();
conn.close();
Use stmt.executeQuery(String sql), it returns ResultSet.
If you want a ResultSet returned you should use executeQuery, not executeUpdate.
The stmt.executeUpdate(query); doesn't fit for an SELECT query.
You need to replace it by stmt.executeQuery(query);
Well the method executeUpdate returns a int not a results set, seen in the documentation here: https://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#executeUpdate(java.lang.String)
the integer being return being either (1) the row count for SQL Data Manipulation Language (DML) statements or (2) 0 for SQL statements that return nothing
the method you are actually want to use is executeQuery and the documentation for that can be found at:
https://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#executeQuery(java.lang.String)
According the Javadoc (https://docs.oracle.com/javase/9/docs/api/java/sql/Statement.html#executeUpdate-java.lang.String-), stmt.executeUpdate(query); returns an int and not a ResultSet object.
From the Javadoc :
Returns:
either (1) the row count for SQL Data Manipulation Language (DML) statements or (2) 0 for SQL statements that return nothing
I think you must use stmt.executeQuery(query); instead, which return the ResultSet you expect. You're doing a SELECT and not an INSERT, UPDATE, or DELETE operation.
I believe people have already answered your question, which is statement.executeUpdate(query) returns the number of how many rows has been affected by executing the query, and you should use statement.executeQuery(query) instead ..
But this part String query = "SELECT * FROM patient WHERE Mobile_No = '" + mobno + "';" is very bad approach, it will leave the door opened for SQL injection, you should use PreparedStatement instead of Statement
I have created such statement:
String query = "INSERT INTO ZMONES (ID, PAVADINIMAS, SLAPTAZODIS) VALUES("
+sum+" ,"+a+", "+b+")";
where variable sum is an integer ID in the database's table and a and b are two string values that are to be added. I am executing this statement as such: stmt.executeUpdate(query);
However this error pops out:
Column 'PERSON' is either not in any table in the FROM list or appers
within a join specification and is outside the scope of the join
specification or appears in a having clause and is not in the GROUP BY
list. If this is a CREATE or ALTER TABLE statement then 'PERSON' is
not a column in the target table.
I do understand that Java interprets it as a column's name, I do not however, understand why this happens? I have searched for in this in stackoverflow and most questions deal with text and not string variables.
The error that you ran into can be corrected easily as follows (assuming sum is a number):
String query = "INSERT INTO ZMONES (ID, PAVADINIMAS, SLAPTAZODIS) VALUES("
+sum+" ,'"+escape(a)+"', '"+escape(b)+"')";
Where escape(String) is the following method:
public String escape(String string) {
// This works in most databases, although some require you to escape apostrophes via \'
return string == null ? null : string.replace("'", "''");
}
A note on SQL injection
But please! Don't do that. Use a PreparedStatement and proper bind variables instead of concatenating your input into your SQL statements. Why?
Because of SQL injection
Because of performance considerations
Here's how:
try (PreparedStatement s = connection.prepareStatement(
"INSERT INTO ZMONES (ID, PAVADINIMAS, SLAPTAZODIS) VALUES (?, ?, ?)")) {
s.setInt(1, sum);
s.setString(2, a);
s.setString(3, b);
s.executeQuery();
}
You need to surround strings with quotation marks:
String query = "INSERT INTO ZMONES (ID, PAVADINIMAS, SLAPTAZODIS) VALUES("+sum+", '"+a+"', '"+b+"')";
I m writing a small utility that captures and logs SQL statements, but will have to remove sensitive data from the Query text and replace with with some dummy text (i.e:XXXXX).
What is a good way to parse the SQL query in java and replace parameters value?
for example:
replace
SELECT NAME, ADDRESS, .... FROM USER WHERE SSN IN ('11111111111111', '22222222222222');
with
SELECT NAME, ADDRESS, .... FROM USER WHERE SSN IN (?, ?);
Using JSQLParser (V0.8.9) this is a solution for your problem:
String sql ="SELECT NAME, ADDRESS, COL1 FROM USER WHERE SSN IN ('11111111111111', '22222222222222');";
Select select = (Select) CCJSqlParserUtil.parse(sql);
//Start of value modification
StringBuilder buffer = new StringBuilder();
ExpressionDeParser expressionDeParser = new ExpressionDeParser() {
#Override
public void visit(StringValue stringValue) {
this.getBuffer().append("XXXX");
}
};
SelectDeParser deparser = new SelectDeParser(expressionDeParser,buffer );
expressionDeParser.setSelectVisitor(deparser);
expressionDeParser.setBuffer(buffer);
select.getSelectBody().accept(deparser);
//End of value modification
System.out.println(buffer.toString());
//Result is: SELECT NAME, ADDRESS, COL1 FROM USER WHERE SSN IN (XXXX, XXXX)
This replaces all found String values within your SQL. To replace other types of data e.g. Long values, override the corresponding visit method in ExpressionDeParser.
Don't use regexp in this case. It turns out quickly to be hard maintainable.
The correct answer depends on how much you want to replace. Something like:
[0-9]{3}-?[0-9]{2}-?[0-9]{4}
will replace social security numbers pretty well. I always take regex code to
regexpal.com
to tweak it and work out bugs.
If you need to replace tons of sensitive information though, and if there are a lot of cases, definitely start looking into using a parser to parse the SQL query string. (such as jsqlparser, as Anirudh recommended.)
String sqlDebit = select * from table where and billing_cycle_start_date between :startDate and :endDate
java:
sqlDebit= sqlDebit.replaceAll(":startDate ", ""+startDate).replaceAll(":endDate", ""+endDate);
With prepare statement you can replace "?" in your query string with your value. Use number to specify which "?" you are referring too. They go by order from right to left.
For example: "SELECT LastName, FirstName FROM Person.Contact WHERE LastName = ? and FirstName = ?"
pstmt.setString(1, "LastNameValue");
pstmt.setString(2, "FirstNameValue");
see full example below:
public static void executeStatement(Connection con) {
try(PreparedStatement pstmt = con.prepareStatement("SELECT LastName, FirstName FROM Person.Contact WHERE LastName = ?");) {
pstmt.setString(1, "Smith");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}
I have created a small 3 tier program, consisting of : front end -> servlet -> database.
Front end I enter some details into a form. They are passed to a servlet, which will render some HTML and display the values entered into the form, while also calling a class DatabaseHelper. The DatabaseHelper then connects and inserts these same values into a table.
I know the values are being passed to the servlet class ok, as they are being displayed in the HTML. So the problem must lie within the prepared statement. Problem is, I cannot see any fault with the statement itself. When I query the table itself, there is no data there.
Database connectivity is functional, as I can insert values into a database using hardcoded statements, just not a prepared statement.
Here is a look at the statement Im using. Any advice is much appreciated.
public void addRegisterDetails(String name, String email, String country, String password, ){
try{
String driver = "com.mysql.jdbc.Driver";
Class.forName(driver).newInstance();
// Make db connection
con = DriverManager.getConnection(url, USERNAME, PASSWORD);
st = con.createStatement();
String query = " INSERT INTO user_information (name, email, country, password)" + " VALUES (?, ?, ?, ?)";
PreparedStatement preparedStmt = con.prepareStatement(query);
preparedStmt.setString (1, name);
preparedStmt.setString (2, email);
preparedStmt.setString (3, country);
preparedStmt.setString (4, password);
preparedStmt.execute();
}catch(ClassNotFoundException ex) {
System.out.println(ex);
}catch(Exception e){
e.printStackTrace();
}
}
Table definition
id| name | email | country | password
all VARCHAR except the id, which is type INT.
You should invoke the method executeUpdate() on the statement object.
Also, I don't see any call to commit the data, any transaction handling. It's fine if you skipped that piece of code for the purpose of this question; otherwise it's quite an important step ( commit if all goes well, rollback for exception scenarios)
Use executeUpdate for database write operations:
preparedStmt.executeUpdate();
Answer: The database ID was not set to auto increment. For some reason this does not allow you to then insert data to table. Thanks to ChadNC for pointing this out.
Also, why st = con.createStatement();?
And why do you have a leading space in your query?
String query = " INSERT INTO user_information (name, email, country, password)"
+ " VALUES (?, ?, ?, ?)";
This leading space may or may not matter...
Lastly, you should be closing your connection when you're through with it, using try-with-resources or a finally block.