I am trying to update a value if record exists else insert the values to database. However, that is not working. I have written the below code.
String sqlCheck = "Select * from [UAP].[dbo].[UAP_EMPLOYEE] where EMP_EMPLOYEE_ID = '"+empId+"' ";
PreparedStatement prpStatementCheck = conn.prepareStatement(sqlCheck);
prpStatementCheck.setString(1, EMP_EMPLOYEE_ID);
ResultSet rsCheck=prpStatementCheck.executeQuery();
String check=null;
while((rsCheck.next())
{
if(rsCheck.next()>0)
update statement;
else
Insert Statement;
}
setString should be used with bound variables:
Your sql string should look like this:
"Select * from [UAP].[dbo].[UAP_EMPLOYEE] where EMP_EMPLOYEE_ID = ?"
What is the version of your SqlServer?
If it is 2008 or higher, you can leverage the UPSERT command.
That condition while((rsCheck.next()) will only be executed if the employee exists.
Otherwise, that code
if(rsCheck.next()>0)
update statement;
else
Insert Statement;
is unreachable.
You could use something like that:
boolean exists = false;
while((rsCheck.next())
{
update statement;
exists = true;
}
if(!exists) insert statement;
As EMP_EMPLOYEE_ID field is an INTEGER type, use setInt rather than setString:
String sqlCheck = "Select * from [UAP].[dbo].[UAP_EMPLOYEE] where EMP_EMPLOYEE_ID = ?";
PreparedStatement prpStatementCheck = conn.prepareStatement(sqlCheck);
prpStatementCheck.setInt(1, EMP_EMPLOYEE_ID);
Related
I'm trying to use prepared statements to set a table name to select data from, but I keep getting an error when I execute the query.
The error and sample code is displayed below.
[Microsoft][ODBC Microsoft Access Driver] Parameter 'Pa_RaM000' specified where a table name is required.
private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [?]"; //?=date
public Execute(String reportDate){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection(Display.DB_MERC);
PreparedStatement st = conn.prepareStatement(query1);
st.setString(1, reportDate);
ResultSet rs = st.executeQuery();
Any thoughts on what might be causing this?
A table name can't be used as a parameter. It must be hard coded. So you can do something like:
private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [" + reportDate + "?]";
If you need a solution which is not vulnerable to SQL injection, you have to duplicate the query for all tables you need:
final static String QUERIES = {
"SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ...",
"SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ...",
"SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ...",
...
};
And yes: the queries are duplicates and only the table name differs.
Now you simply select the query that fits your table, e.g. like
...
PreparedStatement st = conn.prepareStatement(QUERIES[index]);
...
You can use this approach wich JPA, Hibernate, whatever...
If you want a more verbose approach consider using an enum like
enum AQuery {
Table1("SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ..."),
Table2("SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ..."),
Table3("SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ..."),
...
private final String query;
AQuery(final String query) {
this.query = query;
}
public String getQuery() {
return query;
}
}
Now use the either an index
String sql = AQuery.values()[index].getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
Or use a table name
String sql = AQuery.valueOf("Table1").getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
This is technically possible with a workaround, but very bad practice.
String sql = "IF ? = 99\n";
sql += "SELECT * FROM first_table\n";
sql += "ELSE\n";
sql += "SELECT * FROM second_table";
PreparedStatement ps = con.prepareStatement(sql);
And then when you want to select from first_table you set the parameter with
ps.setInt(1, 99);
Or if not, you set it to something else.
As a number of people have said, you can't use a statement parameter for a table name, only for variables as part of the condition.
Based on the fact you have a variable table name with (at least) two table names, perhaps it would be best to create a method which takes the entity you are storing and returns a prepared statement.
PreparedStatement p = createStatement(table);
You can't set table name in prepared statement
As said before, it is not possible to set the table name in a prepared statement with preparedStatement.setString(1, tableName). And it is also not possible to add parts of the SQL query to a prepared statement (eg preparedStatement.addSql(" or xyz is null")).
How to do it right without risking SQL injections?
The table name must be inserted into the SQL (or JQL) query you want to execute with string operations like "select * from " + tableName or String.format("select * from %s", tableName)
But how to avoid SQL injections?
If the table name does not come from user input, you are probably safe.
For example, if you make a decision like here
String tableName;
if(condition) {
tableName = "animal";
} else {
tableName = "plant";
}
final String sqlQuery = "delete from " + tableName;
...
If the table name depends on the users input, you need to check the input manually.
For example, with a white-list containing all valid table names:
if(!tableNamesWhitelist.contains(tableName)) {
throw new IllegalArgumentException(tableName + " is not a valid table name");
}
String sqlQuery = "delete from " + tableName;
or with an enum:
public enum Table {
ANIMAL("animal"),
PLANT("plant");
private sqlTableName;
private TableName(String sqlTableName) {
this.sqlTableName= sqlTableName;
}
public getSqlTableName() {
return sqlTableName;
}
}
and then convert the user-input string like ANIMAL into Table.ANIMAL. An exception is thrown, if no fitting enumeration value does exist.
eg
#DeleteMapping("/{table}")
public String deleteByEnum(#PathVariable("table") Table table) {
final String sqlQuery = "delete from " + table.getSqlTableName();
...
}
Of course these examples work with select, update, ... too and a lot of other implementations to check the user input are possible.
This might help:
public ResultSet getSomething(String tableName) {
PreparedStatement ps = conn.prepareStatement("select * from \`"+tableName+"\`");
ResultSet rs = ps.executeQuery();
}
I'm not sure you can use a PreparedStatement to specify the name of the table, just the value of some fields. Anyway, you could try the same query but, without the brackets:
"SELECT plantID, edrman, plant, vaxnode FROM ?"
String table="pass";
String st="select * from " + table + " ";
PreparedStatement ps=con.prepareStatement(st);
ResultSet rs = ps.executeQuery();
i have store procedure with 1 parameter only. I can execute the procedure like this exec proc_name param1 in microsoft SQL server management studio and show result set that i want. But when i try in java with my code like this:
String url = "jdbc:sqlserver://TOSHIBA\\SQLEXPRESS;databaseName=Perpustakaan;integratedSecurity=true";
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
conn = DriverManager.getConnection(url);
CallableStatement statement = conn.prepareCall("{call search(?)}");
statement.setString(1,parameter);
ArrayList<Buku> result = new ArrayList<>();
statement.execute();
ResultSet rs = statement.executeQuery();
while (rs.next()) {
int tempId = rs.getInt("id");
String tempJudul = rs.getString("judul");
result.add(new Buku(tempId, tempJudul));
}
return result;
i get an error say 'The statement did not return a result set.' The 'parameter' in statement.setString(1,parameter) is String typed.
this is my store procedure code in case something is wrong
alter proc search
#kata varchar(255)
as
declare #tempResult table
(
kata varchar(255)
)
declare
#idx int,
#katas varchar(255)
set #katas = #kata
set #idx = CHARINDEX(',',#katas,1)
while(#idx != 0)
begin
insert into #tempResult
select
SUBSTRING(#katas,1,#idx-1)
set #katas = SUBSTRING(#katas,#idx+1,100000000)
set #idx = CHARINDEX(',',#katas,1)
end
insert into #tempResult
select
#katas
declare #searchResult table
(
judul varchar(255)
)
insert into #searchResult
select dbo.buku.judul
from dbo.buku cross join #tempResult
where CHARINDEX(kata, dbo.buku.judul) > 0
select
dbo.buku.id, sr.judul
from
#searchResult as sr join dbo.buku
on
sr.judul = dbo.buku.judul
group by
sr.judul, dbo.buku.id
order by
COUNT(sr.judul) desc
exec search 'Games'
In order to call stored procedures with callable statement you need to registerOutParameter for the expected results. Also you don't need to executeQuery after the execute becaues you don't have a query and you have already executed your statement
Try to change your code to:
boolean hasResults=statement.execute();
while (hasResults) {
ResultSet rs = cStmt.getResultSet();
int tempId = rs.getInt("id");
String tempJudul = rs.getString("judul");
result.add(new Buku(tempId, tempJudul));
hasResults= cStmt.getMoreResults();
}
But before that you should add the parameters you expect to the statement. Just the way you do :
statement.setString(1,parameter);
// Add out parameters here
statement.registerOutParameter(1, java.sql.Types.INTEGER);
....
I cannot be bothered to look at the procedure call right now ;) but I guess it works if you can execute it in management studio
so what i do to make the statement return result set is i add SET NOCOUNT ON in the beginning of my store procedure.
set nocount explanation is here.
I'm trying to use prepared statements to set a table name to select data from, but I keep getting an error when I execute the query.
The error and sample code is displayed below.
[Microsoft][ODBC Microsoft Access Driver] Parameter 'Pa_RaM000' specified where a table name is required.
private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [?]"; //?=date
public Execute(String reportDate){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection(Display.DB_MERC);
PreparedStatement st = conn.prepareStatement(query1);
st.setString(1, reportDate);
ResultSet rs = st.executeQuery();
Any thoughts on what might be causing this?
A table name can't be used as a parameter. It must be hard coded. So you can do something like:
private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [" + reportDate + "?]";
If you need a solution which is not vulnerable to SQL injection, you have to duplicate the query for all tables you need:
final static String QUERIES = {
"SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ...",
"SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ...",
"SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ...",
...
};
And yes: the queries are duplicates and only the table name differs.
Now you simply select the query that fits your table, e.g. like
...
PreparedStatement st = conn.prepareStatement(QUERIES[index]);
...
You can use this approach wich JPA, Hibernate, whatever...
If you want a more verbose approach consider using an enum like
enum AQuery {
Table1("SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ..."),
Table2("SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ..."),
Table3("SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ..."),
...
private final String query;
AQuery(final String query) {
this.query = query;
}
public String getQuery() {
return query;
}
}
Now use the either an index
String sql = AQuery.values()[index].getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
Or use a table name
String sql = AQuery.valueOf("Table1").getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
This is technically possible with a workaround, but very bad practice.
String sql = "IF ? = 99\n";
sql += "SELECT * FROM first_table\n";
sql += "ELSE\n";
sql += "SELECT * FROM second_table";
PreparedStatement ps = con.prepareStatement(sql);
And then when you want to select from first_table you set the parameter with
ps.setInt(1, 99);
Or if not, you set it to something else.
As a number of people have said, you can't use a statement parameter for a table name, only for variables as part of the condition.
Based on the fact you have a variable table name with (at least) two table names, perhaps it would be best to create a method which takes the entity you are storing and returns a prepared statement.
PreparedStatement p = createStatement(table);
You can't set table name in prepared statement
As said before, it is not possible to set the table name in a prepared statement with preparedStatement.setString(1, tableName). And it is also not possible to add parts of the SQL query to a prepared statement (eg preparedStatement.addSql(" or xyz is null")).
How to do it right without risking SQL injections?
The table name must be inserted into the SQL (or JQL) query you want to execute with string operations like "select * from " + tableName or String.format("select * from %s", tableName)
But how to avoid SQL injections?
If the table name does not come from user input, you are probably safe.
For example, if you make a decision like here
String tableName;
if(condition) {
tableName = "animal";
} else {
tableName = "plant";
}
final String sqlQuery = "delete from " + tableName;
...
If the table name depends on the users input, you need to check the input manually.
For example, with a white-list containing all valid table names:
if(!tableNamesWhitelist.contains(tableName)) {
throw new IllegalArgumentException(tableName + " is not a valid table name");
}
String sqlQuery = "delete from " + tableName;
or with an enum:
public enum Table {
ANIMAL("animal"),
PLANT("plant");
private sqlTableName;
private TableName(String sqlTableName) {
this.sqlTableName= sqlTableName;
}
public getSqlTableName() {
return sqlTableName;
}
}
and then convert the user-input string like ANIMAL into Table.ANIMAL. An exception is thrown, if no fitting enumeration value does exist.
eg
#DeleteMapping("/{table}")
public String deleteByEnum(#PathVariable("table") Table table) {
final String sqlQuery = "delete from " + table.getSqlTableName();
...
}
Of course these examples work with select, update, ... too and a lot of other implementations to check the user input are possible.
This might help:
public ResultSet getSomething(String tableName) {
PreparedStatement ps = conn.prepareStatement("select * from \`"+tableName+"\`");
ResultSet rs = ps.executeQuery();
}
I'm not sure you can use a PreparedStatement to specify the name of the table, just the value of some fields. Anyway, you could try the same query but, without the brackets:
"SELECT plantID, edrman, plant, vaxnode FROM ?"
String table="pass";
String st="select * from " + table + " ";
PreparedStatement ps=con.prepareStatement(st);
ResultSet rs = ps.executeQuery();
This question already has answers here:
Using Prepared Statements to set Table Name
(8 answers)
Closed 7 years ago.
Is there a limit to PreparedStatement variables (?) or requirements for their placement?
I have a method that takes in the parameters to complete a PreparedStatement however, it throws a SQLException.
Here is the PreparedStatement I want to use:
String update = "UPDATE ? SET ? = ? WHERE UserID = ?";
When I add in the first and second variables it runs just fine. Here is the working PreparedStatement:
String update = "UPDATE Student SET First_Name = ? WHERE UserID = ?";
Is there a reason I cannot get the first statement to work?
The entire method:
public static void runUpdate(String givenID, String givenAttribute, String givenUpdate) throws SQLException
{
// Establish the connection with the database
Connection conn = SimpleDataSource.getConnection();
try
{
// Create a string with the SQL Update statement
String update = "UPDATE ? SET ? = ? WHERE UserID = ?";
// Make a Prepared Statement with the connection to the database
PreparedStatement stat = conn.prepareStatement(update);
try
{
// Set the statement with the given parameters
stat.setString(1, Utility.getType(givenID));
stat.setString(2, givenAttribute);
stat.setString(2, givenUpdate);
stat.setString(3, givenID);
// Execute the Update Statement
stat.executeUpdate();
}
finally
{
// Close the prepared Statement
stat.close();
}
}
finally
{
// Close the connection to the database
conn.close();
}
}
You can't use the query like this.
String update = "UPDATE ? SET ? = ? WHERE UserID = ?";
You should write the name of table and the name of the column like here.
String update = "UPDATE table SET column_name = ? WHERE UserID = ?";
You can use variables in prepared statements only as placeholder of literals in SQL statements. So you cannot use them for column name, or table names. For these you should resort to dynamic SQL statements.
Why is this not working for me? I keep getting the error:
java.sql.SQLException: Can not issue data manipulation statements with executeQuery().
My code:
private void speler_deleteActionPerformed(java.awt.event.ActionEvent evt) {
int row = tbl_spelers.getSelectedRow();
int SpelerID = (int) tbl_spelers.getValueAt(row, 0);
Speler speler = new Speler();
try {
DBClass databaseClass = new DBClass();
Connection connectie = databaseClass.getConnection();
// NOG ONVEILIG - WACHTEN OP DB SELECT IN DBCLASS!!!
String deleteQry = "DELETE FROM `Speler` WHERE SpelerID = " + SpelerID + ";";
ResultSet rs = databaseClass.GetFromDB(deleteQry);
} catch (SQLException ex) {
Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
You have to use excuteUpdate() for delete.
Docs of excuteUpdate()
Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement.
Where as executeQuery()
Executes the given SQL statement, which returns a single ResultSet object.
Firstly, you need to use excuteUpdate() for the delete, and next
String deleteQry = "DELETE FROM `Speler` WHERE SpelerID = " + SpelerID + ";";
remove the semi-colon and the "`" which encloses the table name "Speler", from the query.
You need to execute you query using executeUpdate()
Also, you just need to make a slight adjustment to your String deleteQry as follows:
String deleteQry = "DELETE FROM Speler WHERE SpelerID = " + SpelerID;
Hope this helps...
executeQuery() method of jdbc is to select records, you can use executeUpdate() for update operations. Please refer to the documentation for the purpose/ intent of each method:
boolean execute()
Executes the SQL statement in this PreparedStatement object, which may
be any kind of SQL statement.
ResultSet executeQuery()
Executes the SQL query in this PreparedStatement object and returns
the ResultSet object generated by the query.
int executeUpdate()
Executes the SQL statement in this PreparedStatement object, which
must be an SQL INSERT, UPDATE or DELETE statement; or an SQL statement
that returns nothing, such as a DDL statement.