Hi I'm using preparedStatement in Java to execute query in DB.
The table:
When it comes to update, delete and insert it's all fine, however when it comes to select( ex. I've done "SELECT ?,?,?,?,? from person" and set strings afterwards) and the following result is returned:
I'm assuming that because it's the strings that are replacing ? so it did not come out as expected:(please correct me if it's wrong)
Expected sql: "SELECT no,name,tel,birthday,address FROM person"
Actual sql: "SELECT \"no\",\"name\",\"birthday\",\"address\" FROM person"
I've tested the second one in in Navicat:
I'd like to understand that why executing this query statement would return a result like this?
If it would help here's Java code:
// Data Assist Object
public class DAO {
static String jdbcurl;
static String username;
static String password;
static{
try {
Class.forName("com.mysql.jdbc.Driver");
ResourceBundle rb = ResourceBundle.getBundle("db");
jdbcurl = rb.getString("jdbcurl");
username = rb.getString("username");
password = rb.getString("password");
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
// for insert, delete and update
public int modify(String sql, String[] args){
int x=0;
try(Connection con = DriverManager.getConnection( jdbcurl,username ,password);
PreparedStatement ps = con.prepareStatement(sql);){
for (int i = 0; i < args.length; i++) {
ps.setString(i+1, args[i]);
}
x =ps.executeUpdate();
System.out.println(x);
}catch(SQLException e){
e.printStackTrace();
}
return x;
}
// for select
public List<Map<String,String>> query(String sql, String[] params){
List<Map<String,String>> resList = new ArrayList<>();
try(Connection con = DriverManager.getConnection( jdbcurl,username ,password);
PreparedStatement ps = con.prepareStatement(sql);){
for (int i = 0; i < params.length; i++) {
ps.setString(i+1, params[i]);
}
try(ResultSet res =ps.executeQuery();){
ResultSetMetaData mdata = res.getMetaData();
int num = mdata.getColumnCount();
while(res.next()){
HashMap<String,String> data = new HashMap<>();
for (int i = 1; i <= num; i++) {
String result = res.getString(i);
String columnName = mdata.getColumnName(i);
data.put(columnName,result);
}
resList.add(data);
}
}
}catch(Exception e){
e.printStackTrace();
}
return resList;
}
public static void main(String[] args) throws SQLException {
DAO dao = new DAO();
String sql = "insert into person(name,tel,birthday,address) values(?,?,?,?)";
sql = "select ?,?,?,?,? from person";
List<Map<String,String>> res = dao.query(sql, new String[]{"no","name","tel","birthday","address"});
for(Map m:res){
System.out.print("no: "+m.get("no")+",");
System.out.print("name: "+m.get("name")+",");
System.out.print("tel: "+m.get("tel")+",");
System.out.print("birthday: "+m.get("birthday")+",");
System.out.println("address: "+m.get("address"));
}
}
}
Thanks for any help.
SQL basically works on a show me these columns where this criteria is true basis.
In the statement:
"SELECT \"no\",\"name\",\"birthday\",\"address\" FROM person"
You're getting
SELECT "no", "name", "birthday", "address" FROM person
when it actually hits the database. The "" operator creates a string in SQL. In plain English, that means that you're telling the database to return that specified set of strings for each row in person where the criteria you listed is met.
Since you didn't list a where clause, all rows are true by default so you get one row of strings for every single row in the person table. The first query is the same thing, but instead of directly passing the strings, you're adding them in as bind variables.
If you actually want to see the values in the table, write the query without the "'s
SELECT no, name, birthday, address FROM person
Unless otherwise specified, bind functions generally pass the value as a string. Which is why the query behaved the way it did. I don't recommend using bind variables in the select clause. That's a strange practice.
Edit:
As Adrian pointed out in the comments, " denotes columns in SQL. My apologies for not catching that. I assume that you meant to use the ' operator which actually denotes strings.
If not, something else is going on here entirely.
For the select you use the question marks in the WHERE clause, not where you list the fields you need as output.
Replace
sql = "select ?,?,?,?,? from person";
with
sql = "select no,name,tel,birthday,address from person";
For this particular query there is no binding to do. It will retrieve all the records from the table.
I want to INSERT a record in a database (which is Microsoft SQL Server in my case) using JDBC in Java. At the same time, I want to obtain the insert ID. How can I achieve this using JDBC API?
If it is an auto generated key, then you can use Statement#getGeneratedKeys() for this. You need to call it on the same Statement as the one being used for the INSERT. You first need to create the statement using Statement.RETURN_GENERATED_KEYS to notify the JDBC driver to return the keys.
Here's a basic example:
public void create(User user) throws SQLException {
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(SQL_INSERT,
Statement.RETURN_GENERATED_KEYS);
) {
statement.setString(1, user.getName());
statement.setString(2, user.getPassword());
statement.setString(3, user.getEmail());
// ...
int affectedRows = statement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
user.setId(generatedKeys.getLong(1));
}
else {
throw new SQLException("Creating user failed, no ID obtained.");
}
}
}
}
Note that you're dependent on the JDBC driver as to whether it works. Currently, most of the last versions will work, but if I am correct, Oracle JDBC driver is still somewhat troublesome with this. MySQL and DB2 already supported it for ages. PostgreSQL started to support it not long ago. I can't comment about MSSQL as I've never used it.
For Oracle, you can invoke a CallableStatement with a RETURNING clause or a SELECT CURRVAL(sequencename) (or whatever DB-specific syntax to do so) directly after the INSERT in the same transaction to obtain the last generated key. See also this answer.
Create Generated Column
String generatedColumns[] = { "ID" };
Pass this geneated Column to your statement
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Use ResultSet object to fetch the GeneratedKeys on Statement
ResultSet rs = stmtInsert.getGeneratedKeys();
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("Inserted ID -" + id); // display inserted record
}
When encountering an 'Unsupported feature' error while using Statement.RETURN_GENERATED_KEYS, try this:
String[] returnId = { "BATCHID" };
String sql = "INSERT INTO BATCH (BATCHNAME) VALUES ('aaaaaaa')";
PreparedStatement statement = connection.prepareStatement(sql, returnId);
int affectedRows = statement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
try (ResultSet rs = statement.getGeneratedKeys()) {
if (rs.next()) {
System.out.println(rs.getInt(1));
}
rs.close();
}
Where BATCHID is the auto generated id.
I'm hitting Microsoft SQL Server 2008 R2 from a single-threaded JDBC-based application and pulling back the last ID without using the RETURN_GENERATED_KEYS property or any PreparedStatement. Looks something like this:
private int insertQueryReturnInt(String SQLQy) {
ResultSet generatedKeys = null;
int generatedKey = -1;
try {
Statement statement = conn.createStatement();
statement.execute(SQLQy);
} catch (Exception e) {
errorDescription = "Failed to insert SQL query: " + SQLQy + "( " + e.toString() + ")";
return -1;
}
try {
generatedKey = Integer.parseInt(readOneValue("SELECT ##IDENTITY"));
} catch (Exception e) {
errorDescription = "Failed to get ID of just-inserted SQL query: " + SQLQy + "( " + e.toString() + ")";
return -1;
}
return generatedKey;
}
This blog post nicely isolates three main SQL Server "last ID" options:
http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the-sql-server/ - haven't needed the other two yet.
Instead of a comment, I just want to answer post.
Interface java.sql.PreparedStatement
columnIndexes « You can use prepareStatement function that accepts columnIndexes and SQL statement.
Where columnIndexes allowed constant flags are Statement.RETURN_GENERATED_KEYS1 or Statement.NO_GENERATED_KEYS[2], SQL statement that may contain one or more '?' IN parameter placeholders.
SYNTAX «
Connection.prepareStatement(String sql, int autoGeneratedKeys)
Connection.prepareStatement(String sql, int[] columnIndexes)
Example:
PreparedStatement pstmt =
conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
columnNames « List out the columnNames like 'id', 'uniqueID', .... in the target table that contain the auto-generated keys that should be returned. The driver will ignore them if the SQL statement is not an INSERT statement.
SYNTAX «
Connection.prepareStatement(String sql, String[] columnNames)
Example:
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Full Example:
public static void insertAutoIncrement_SQL(String UserName, String Language, String Message) {
String DB_URL = "jdbc:mysql://localhost:3306/test", DB_User = "root", DB_Password = "";
String insertSQL = "INSERT INTO `unicodeinfo`( `UserName`, `Language`, `Message`) VALUES (?,?,?)";
//"INSERT INTO `unicodeinfo`(`id`, `UserName`, `Language`, `Message`) VALUES (?,?,?,?)";
int primkey = 0 ;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(DB_URL, DB_User, DB_Password);
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
pstmt.setString(1, UserName );
pstmt.setString(2, Language );
pstmt.setString(3, Message );
if (pstmt.executeUpdate() > 0) {
// Retrieves any auto-generated keys created as a result of executing this Statement object
java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys();
if ( generatedKeys.next() ) {
primkey = generatedKeys.getInt(1);
}
}
System.out.println("Record updated with id = "+primkey);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
I'm using SQLServer 2008, but I have a development limitation: I cannot use a new driver for it, I have to use "com.microsoft.jdbc.sqlserver.SQLServerDriver" (I cannot use "com.microsoft.sqlserver.jdbc.SQLServerDriver").
That's why the solution conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) threw a java.lang.AbstractMethodError for me.
In this situation, a possible solution I found is the old one suggested by Microsoft:
How To Retrieve ##IDENTITY Value Using JDBC
import java.sql.*;
import java.io.*;
public class IdentitySample
{
public static void main(String args[])
{
try
{
String URL = "jdbc:microsoft:sqlserver://yourServer:1433;databasename=pubs";
String userName = "yourUser";
String password = "yourPassword";
System.out.println( "Trying to connect to: " + URL);
//Register JDBC Driver
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
//Connect to SQL Server
Connection con = null;
con = DriverManager.getConnection(URL,userName,password);
System.out.println("Successfully connected to server");
//Create statement and Execute using either a stored procecure or batch statement
CallableStatement callstmt = null;
callstmt = con.prepareCall("INSERT INTO myIdentTable (col2) VALUES (?);SELECT ##IDENTITY");
callstmt.setString(1, "testInputBatch");
System.out.println("Batch statement successfully executed");
callstmt.execute();
int iUpdCount = callstmt.getUpdateCount();
boolean bMoreResults = true;
ResultSet rs = null;
int myIdentVal = -1; //to store the ##IDENTITY
//While there are still more results or update counts
//available, continue processing resultsets
while (bMoreResults || iUpdCount!=-1)
{
//NOTE: in order for output parameters to be available,
//all resultsets must be processed
rs = callstmt.getResultSet();
//if rs is not null, we know we can get the results from the SELECT ##IDENTITY
if (rs != null)
{
rs.next();
myIdentVal = rs.getInt(1);
}
//Do something with the results here (not shown)
//get the next resultset, if there is one
//this call also implicitly closes the previously obtained ResultSet
bMoreResults = callstmt.getMoreResults();
iUpdCount = callstmt.getUpdateCount();
}
System.out.println( "##IDENTITY is: " + myIdentVal);
//Close statement and connection
callstmt.close();
con.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
try
{
System.out.println("Press any key to quit...");
System.in.read();
}
catch (Exception e)
{
}
}
}
This solution worked for me!
I hope this helps!
You can use following java code to get new inserted id.
ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, quizid);
ps.setInt(2, userid);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
lastInsertId = rs.getInt(1);
}
It is possible to use it with normal Statement's as well (not just PreparedStatement)
Statement statement = conn.createStatement();
int updateCount = statement.executeUpdate("insert into x...)", Statement.RETURN_GENERATED_KEYS);
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
return generatedKeys.getLong(1);
}
else {
throw new SQLException("Creating failed, no ID obtained.");
}
}
Most others have suggested to use JDBC API for this, but personally, I find it quite painful to do with most drivers. When in fact, you can just use a native T-SQL feature, the OUTPUT clause:
try (
Statement s = c.createStatement();
ResultSet rs = s.executeQuery(
"""
INSERT INTO t (a, b)
OUTPUT id
VALUES (1, 2)
"""
);
) {
while (rs.next())
System.out.println("ID = " + rs.getLong(1));
}
This is the simplest solution for SQL Server as well as a few other SQL dialects (e.g. Firebird, MariaDB, PostgreSQL, where you'd use RETURNING instead of OUTPUT).
I've blogged about this topic more in detail here.
With Hibernate's NativeQuery, you need to return a ResultList instead of a SingleResult, because Hibernate modifies a native query
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
like
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
if you try to get a single result, which causes most databases (at least PostgreSQL) to throw a syntax error. Afterwards, you may fetch the resulting id from the list (which usually contains exactly one item).
In my case ->
ConnectionClass objConnectionClass=new ConnectionClass();
con=objConnectionClass.getDataBaseConnection();
pstmtGetAdd=con.prepareStatement(SQL_INSERT_ADDRESS_QUERY,Statement.RETURN_GENERATED_KEYS);
pstmtGetAdd.setString(1, objRegisterVO.getAddress());
pstmtGetAdd.setInt(2, Integer.parseInt(objRegisterVO.getCityId()));
int addId=pstmtGetAdd.executeUpdate();
if(addId>0)
{
ResultSet rsVal=pstmtGetAdd.getGeneratedKeys();
rsVal.next();
addId=rsVal.getInt(1);
}
If you are using Spring JDBC, you can use Spring's GeneratedKeyHolder class to get the inserted ID.
See this answer...
How to get inserted id using Spring Jdbctemplate.update(String sql, obj...args)
If you are using JDBC (tested with MySQL) and you just want the last inserted ID, there is an easy way to get it. The method I'm using is the following:
public static Integer insert(ConnectionImpl connection, String insertQuery){
Integer lastInsertId = -1;
try{
final PreparedStatement ps = connection.prepareStatement(insertQuery);
ps.executeUpdate(insertQuery);
final com.mysql.jdbc.PreparedStatement psFinal = (com.mysql.jdbc.PreparedStatement) ps;
lastInsertId = (int) psFinal.getLastInsertID();
connection.close();
} catch(SQLException ex){
System.err.println("Error: "+ex);
}
return lastInsertId;
}
Also, (and just in case) the method to get the ConnectionImpl is the following:
public static ConnectionImpl getConnectionImpl(){
ConnectionImpl conexion = null;
final String dbName = "database_name";
final String dbPort = "3306";
final String dbIPAddress = "127.0.0.1";
final String connectionPath = "jdbc:mysql://"+dbIPAddress+":"+dbPort+"/"+dbName+"?autoReconnect=true&useSSL=false";
final String dbUser = "database_user";
final String dbPassword = "database_password";
try{
conexion = (ConnectionImpl) DriverManager.getConnection(connectionPath, dbUser, dbPassword);
}catch(SQLException e){
System.err.println(e);
}
return conexion;
}
Remember to add the connector/J to the project referenced libraries.
In my case, the connector/J version is the 5.1.42. Maybe you will have to apply some changes to the connectionPath if you want to use a more modern version of the connector/J such as with the version 8.0.28.
In the file, remember to import the following resources:
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.mysql.jdbc.ConnectionImpl;
Hope this will be helpful.
Connection cn = DriverManager.getConnection("Host","user","pass");
Statement st = cn.createStatement("Ur Requet Sql");
int ret = st.execute();
There is an error on the line that says ps = stmt.executeQuery();....the error says method executeQuery in interface Statement cannot be applied to given types;
required: String
found: no arguments
reason: actual and formal argument lists differ in length
But whenever I pass a String through that line I get an error saying java.sql.SQLException:Method 'executeQuery(String)' not allowed on prepared statement...
This method is for a button that adds all the Integer values in a column of SQL table.
private void btnCalculateActionPerformed(java.awt.event.ActionEvent evt) {
try{
String SQL = "SELECT SUM(PRICE) FROM MENU";
stmt = con.prepareStatement(SQL);
ps = stmt.executeQuery();
if(ps.next()) {
String total = ps.getString("SUM(PRICE)");
textTotalCost.setText(total);
}
}
catch (SQLException err) {
JOptionPane.showMessageDialog(null, err);
}
}
Column name is must while getting a data
Thanks
Updated following the question change
There is no column name explicitly specified for the calculated column SUM(PRICE) in your SQL statement. It would hardly ever actually be "SUM(PRICE)". Try naming your column. Also prepareStatement is useful when passing parameters. Simple Select does not need it:
private void btnCalculateActionPerformed(java.awt.event.ActionEvent evt) {
try{
String SQL = "SELECT SUM(PRICE) As PRICE_TOTAL FROM MENU";
Statement stmt = con.createStatement();
ResultSet ps = stmt.executeQuery(SQL);
if(ps.next()) {
String total = ps.getString("PRICE_TOTAL");
textTotalCost.setText(total);
}
}
catch (SQLException err) {
JOptionPane.showMessageDialog(null, err);
}
}
or access the value by column index rather than name:
private void btnCalculateActionPerformed(java.awt.event.ActionEvent evt) {
try{
String SQL = "SELECT SUM(PRICE) FROM MENU";
Statement stmt = con.createStatement();
ResultSet ps = stmt.executeQuery(SQL);
if(ps.next()) {
String total = ps.getString(0);
textTotalCost.setText(total);
}
}
catch (SQLException err) {
JOptionPane.showMessageDialog(null, err);
}
}
I don't fully understand your description but I think you are trying to assign the PreparedStatement created in
stmt = con.prepareStatement(SQL)
to a variable of type Statement (stmt) and that's causing the error. The line of code above works because PreparedStatement is an extension (or implementation) of Statement but
ps = stmt.executeQuery();
fails because the class Statement doesn't have an executeQuery method without parameters, PreparedStatement does.
#Y.B.'s solution and the rest of recommendations are good (the alias for sum(price) or getting the value by column index) if it's ok using a regular Statement. The alternative is changing the type of stmt to PreparedStatement in your original code.
I have my Java program and I need to get data from my MYSQL DB,
I wrote this one out but its just sysout so getting data from my class and not using the Prepared Statement (I can delete the first 3 lines and it will work the same )
Could use some help to figure out how to get data from my DB and print it out
public void viewClientDetails(ClientsBean client) {
try {
PreparedStatement ps = connect.getConnection().prepareStatement(
"SELECT * FROM mbank.clients WHERE client_id = ?");
ps.setLong(1, client.getClient_id());
System.out.println(client.getClient_id());
System.out.println(client.getName());
System.out.println(client.getType());
System.out.println(client.getPhone());
System.out.println(client.getAddress());
System.out.println(client.getEmail());
System.out.println(client.getComment());
} catch (SQLException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null,
"Problem occurs while trying to see client details");
}
}
Well you're not actually executing the prepared statement... you're just preparing it. You should call PreparedStatement.executeQuery and use the ResultSet it returns:
// ...code as before...
try (ResultSet results = ps.executeQuery()) {
while (results.next()) {
// Use results.getInt etc
}
}
(You should use a try-with-resources statement to close the PreparedStatement too - or a manual try/finally block if you're not using Java 7.)
You need to do executeQuery on the preparedstatement to get a result set back of the query you performed.
You are simply not executing the query. Add a PreparedStatement.executeQuery() call. And fetch the results from the returned ResultSet.
For example:
PreparedStatement ps = connect.getConnection().prepareStatement("SELECT * FROM mbank.clients WHERE client_id = ?");
ps.setLong(1, client.getClient_id());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String userid = rs.getString("id");
String username = rs.getString("name");
}
As #Jon Skeet pointed out, the declaration of ResultSet in Java 7 is updated to:
public interface ResultSet extends Wrapper, AutoCloseable
It is AutoClosable now, which means that you can and should use the try-with-resource pattern.
You can do the below.
PreparedStatement ps = connect.getConnection().prepareStatement(
"SELECT * FROM mbank.clients WHERE client_id = ?");
resultSet = ps.executeQuery();
while (resultSet.next()) {
String user = resultSet.getString("<COLUMN_1>");
String website = resultSet.getString("<COLUMN_2>");
String summary = resultSet.getString("<COLUMN_3>");
}
I want to create a method when i passed a value to the parameter, it will be passed to the sql statement.
here is what i've tried:
import java.sql.*;
import java.util.*;
import java.text.*;
public class cobadatabase{
protected String sn,fn,ln;
private Connection conn;
private PreparedStatement st;
public cobadatabase(String studentnumber)
{
try{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost/studentrecords","root","");
st = conn.prepareStatement("SELECT * FROM student WHERE Student_Number=?");
ResultSet rs = st.executeQuery();
while (rs.next()){
sn = rs.getString(1);
fn = rs.getString(2);
ln = rs.getString(3);
SimpleDateFormat ft = new SimpleDateFormat("kk:mm:ss");
ft.format(rs.getTime("Total Time").getTime());
}
}
catch(Exception e){
e.printStackTrace();
}
i don't know what is wrong with my code. I just want to retrieve the data for printing
You haven't set parameter in prepareStatement
st = conn.prepareStatement("SELECT * FROM student WHERE Student_Number=?");
// You need to set the parameter for `?`
st.setString(1, studentnumber); // Add this code in between..
ResultSet rs = st.executeQuery();
And actually that is not a method.. that is a Constructor you are using.. And you are using it for wrong purpose..
Technically, the sole purpose of a Constructor is to initialize the attributes of the object being created, or initialize the environment for use..
For using database query, or doing any other kind of task, you should use a method, and invoke that..
I guess you mean something like that:
public String Func (String par1, String par2) throws SQLException {
String query;
query ="SELECT ... WHERE COLUMN_NAME between +"'"+par1+"'"+" AND " +"'"+par2+"'"+...";
rs = st.executeQuery(query); // get data or just Execute without getting results
Pay attention that Between a String there should be a " '' " (non-doubled quotes), whereas numeric values shouldn't.