Am trying to select record from database where record id NOT IN list.
take a look # my problem below.
String Sqlids = "2,6,3,9"; // this is dynamic so the number of element is unknown
String str= "SELECT TOP 1 * FROM student WHERE ID NOT IN (2,6,3,9) ORDER BY NEWID()";
PreparedStatement stat = con.prepareStatement(str);
ResultSet rs = stat.executeQuery();
The above statement work FINE, but if i change it to
String Sqlids = "2,6,3,9";
String str= "SELECT TOP 1 * FROM student WHERE ID NOT IN (Sqlids) ORDER BY NEWID()";
PreparedStatement stat = con.prepareStatement(str);
ResultSet rs = stat.executeQuery();
//i also try this
String Sqlids = "2,6,3,9";
String str= "SELECT TOP 1 * FROM student WHERE ID NOT IN (?) ORDER BY NEWID()";
PreparedStatement stat = con.prepareStatement(str);
stat.setString(1,Sqlids );
ResultSet rs = stat.executeQuery();
THE ABOVE STATEMENT DOESN'T FILTER
Since Sqlids is one string is seeing it as one parameter so it return repeated rows, is there an integer format for storing values like 2,6,3,9 ?
since the Sqlids is from an arraylist called SqlidList
i try somtin like this
Iterator iTr = SqlidList.iterator();
while(iTr.hasNext()){
stat.setString(1,iTr.next().toString()+",");
}
but the setString(1,--) is not available since is in a while loop
Use Connection#createArrayOf after converting your ids to a String[]
String[] ids = {"2", "6", "3", "9"};
String str= "SELECT TOP 1 * FROM student WHERE ID NOT IN ? ORDER BY NEWID()";
PreparedStatement stat = con.prepareStatement(str);
stat.setArray(1, con.createArrayOf("text",ids));
ResultSet rs = stat.executeQuery();
If createArrayOf is not supported by your JDBC driver (as in this case) I'd probably just construct the query string in place e.g:
String Sqlids = "2,6,3,9";
String str= "SELECT TOP 1 * FROM student WHERE ID NOT IN ("+Sqlids+") ORDER BY NEWID()";
or if you have a collection of ids use a utility method to create the array content:
public static String toSqlArray(List<String> strings) {
StringBuilder sb = new StringBuilder();
boolean doneOne = false;
for(String str: strings){
if(doneOne){
sb.append(", ");
}
sb.append("'").append(str).append("'");
doneOne = true;
}
return sb.toString();
}
The way I've solved the problem is :
SQL = "...WHERE ID NOT IN ({0}) ..."
have a method which builds a string containing a number of ? equal to the size of SqlidList
public static String buildQuestionMarks(final int count) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; i++) {
sb.append("?" + ",");
}
return sb.substring(0, sb.length() - 1);
}
use java.text.MessageFormat.format() to insert the list of ? into the sql
String finalSql = MessageFormat.format(SQL, questionMarksString);
have a method to set the params on teh prepared statement. Something similar to what you wrote although you need to increment the first parameter of stat.setString()
This should work for variable number of parameters.
Did you tried using
int[] array = {2,6,3,9};
String str= "SELECT TOP 1 * FROM student WHERE ID NOT IN (?,?,?,?) ORDER BY NEWID()";
PreparedStatement stat = con.prepareStatement(str);
for(int i = 1; i <= array.length; i++)
stat.setString(i,array[i - 1]);
ResultSet rs = stat.executeQuery();
Related
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.
This question already has an answer here:
Passing an Array to a SQL query using Java's PreparedStatement
(1 answer)
Closed 7 years ago.
I am using mySQL JDBC driver in my java program. I want to pass a ArrayList in the IN clause in my SQL query.
i did use a prepared statement like this, but this throws an
"java.sql.SQLFeatureNotSupportedException"exception
since mysql doesn't support this.
ArrayList<String> list = new ArrayList<String>();
PreparedStatement pstmt =
conn.prepareStatement("select * from employee where id in (?)");
Array array = conn.createArrayOf("VARCHAR", list.toArray());
pstmt.setArray(1, array);
ResultSet rs = pstmt.executeQuery();
Is there any other way to do this ? Maybe with Statement stmt.
Build the SQL statement with the correct number of markers, and set all the values.
Beware: Databases have a limit to the number of parameters allowed, though it's very high for MySQL (65535).
char[] markers = new char[list.size() * 2 - 1];
for (int i = 0; i < markers.length; i++)
markers[i] = (i & 1 == 0 ? '?' : ',');
String sql = "select * from employee where id in (" + markers + ")";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int idx = 1;
for (String value : list)
stmt.setString(idx++, value);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
// code here
}
}
}
I have got three fields
String stateID = "";
String districtID = "";
String talukaID = "";
These three fields can be empty Or can have value
The description of the table is
desc tbl_dealer
contactName
phone1
stateID
districtID
talukMandalID
Based on the values recivied , i have to write an SQL Query dynamically
Based on the values recivied , i have to write an SQL Query dynamically
For example
if all three are empty
select contactName , phone1 from tbl_dealer
If stateID is empty then (removing state from the query)
select contactName , phone1 from tbl_dealer where districtID = "'+districtID+'" AND talukaID = "'+talukaID+'"
And similarly for all the cases
Could you please let me know how can to wrie this efficiently ,
I would suggest, first create a method :
private void appendFilter(StringBuilder sb, String fieldName, String fieldValue) {
if(fieldValue != null && !fieldValue.trim().equalsIgnoreCase("")) {
sb.append("AND "+fieldName+"='"+fieldValue+"'");
}
}
Then use this method:
StringBuilder sb = new StringBuilder();
sb.append("select contactName , phone1 from tbl_dealer where 1=1 ");
appendFilter(sb, "districtID", districtID);
appendFilter(sb, "stateID", stateID);
appendFilter(sb, "talukaID", talukaID);
final String query=sb.toString();
You should use a PreparedStatement with bind variables to eliminate the chance of SQL injection (and to enable the DB to cache the query):
PreparedStatement ps = null;
try {
List<String> bindVariables = new ArrayList<>();
StringBuilder query = new StringBuilder(
"select contactName, phone1 from tbl_dealer WHERE 1=1");
if (stateID.length > 0) {
query.append(" AND stateID = ?");
bindVariables.add(stateID);
}
if (districtID.length > 0) {
query.append(" AND districtID = ?");
bindVariables.add(districtID);
}
if (talukaID.length > 0) {
query.append(" AND talukaID = ?");
bindVariables.add(talukaID);
}
ps = myConnection.prepareStatement(query.toString());
for (int i = 0; i < bindVariables.size(); i++) {
// variables are indexed from 1 in JDBC
ps.setString(i+1, bindVariables.get(i));
}
ResultSet rs = ps.executeQuery();
// iterate over the result set here
rs.close();
} finally {
if (ps != null) {
ps.close();
}
}
There's some duplication in the code that could be removed by introducing a helper method, if you were to use more columns in the WHERE condition.
I have a dynamic number of data values in an array fetched from an HTML form.
Now I want to update my table with these data.
The column names are column1 , column2 ... and so on;
I have data in the array[] and number of columns to update in unumber
I am using this code but its not working.
P.S: I am new to coding so it might be naive.
for(int i=1; i<=unumber; i++)
{
String username = "someuser";
String column = "column" + Integer.toString(i);
PreparedStatement pr = null;
String query1 = "update table1 set (?) = (?) where username = (?)";
pr = con.prepareStatement(query1);
pr.setString(1, column);
pr.setString(2, array[i]);
pr.setString(3, someuser);
int s = pr.executeUpdate();
}
AFAIK, you can't use "prepared statements" for this. You can resolve it by performing the insertion in the query yourself:
String query1 = "update table1 set "+column+" = ? where username = ?";
pr = con.prepareStatement(query1);
pr.setString(1, array[i]);
pr.setString(2, someuser);
But be aware of sql injection. You better check whether the possible values of column can't be altered. Validate all input that leads to determining the column name.
Make sure a user can't specify the column his/herself: otherwise one could for instance set the column to password and set a password for some user. And then login with that password. Or one could try to set the column to '; drop table foo; select * where x
PreparedStatments can only bind values, not syntactic elements or object names, like columns, so this approach won't work. You'll have to fall back to string manipulation:
for(int i=0; i<unumber; i++) {
String username = "someuser";
String column = "column" + Integer.toString(i);;
PreparedStatement pr = null;
String query1 = "update table1 set " + column + " = (?) where username = (?)";
pr = con.prepareStatement(query1);
pr.setString(1, column);
pr.setString(2, someuser);
int s = pr.executeUpdate();
}
Moreover, since you're updating several columns with the same where clause, you could loop over the columns and construct just one update statement. It will force you to have two loops (one for constructing the query and one for binding the values once the query is prepared), but it should still be considerably faster, as you're accessing the database only once instead of N times:
String username = "someuser";
StringBuilder sql = new StringBuilder("update table1 set ");
for(int i=0; i < unumber; i++) {
sql.append("column")
.append(i).
.append(" = ?");
if (i != (unumber - 1)) {
sql.append(", ");
}
}
sql.append("where username = (?)");
PreparedStatement pr = con.prepareStatement(sql.toString());
for(int i = 0; i < unumber; i++) {
pr.setString(i, array[i]);
}
pr.setString(unumber, someuser);
int s = pr.executeUpdate();
I try to write a code for make a SELECT on MySql DB like this
SELECT MESE,IMPORTO,ANNO FROM VISTASTATISTICHEMENSILI WHERE ANNO in(?)
So, I would like to pass a list of Integer value like this:
PreparedStatement stmt = db.prepareStatement(queryDettaglio);
Integer[] myArr = new Integer[2];
myArr[0] = 1;
myArr[1] = 2;
stmt.setArray(1, db.createArrayOf("INTEGER", myArr));
ResultSet rs = stmt.executeQuery();
So, when I try to run this code I have this error:
DEBUG [AWT-EventQueue-0] (MyLog4J.java:45) - java.sql.SQLFeatureNotSupportedException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:310)
at com.mysql.jdbc.SQLError.notImplemented(SQLError.java:1332)
at com.mysql.jdbc.JDBC4Connection.createArrayOf(JDBC4Connection.java:58)
When I fix it?
Reguards
You can not pass an array to a ? in a prepared statement. The correct way to do it and avoid all chance of injection attack is like this:
StringBuilder idList = new StringBuilder()
for (int id : myArr) {
if (idList.length() > 0) {
idList.append(",");
}
idList.append("?");
}
PreparedStatement ps = con.prepareStement("SELECT MESE,IMPORTO,ANNO FROM VISTASTATISTICHEMENSILI WHERE ANNO in("+idList+");
for (int i = 0; i < myArr.length; i++) {
ps.setInt(i+1,myArr[i]);
}
Basically you are building a prepared statement with the right number of ? marks and then setting the parameters in.
Because myArr is declared as an Integer[] array, you can also just do this:
StringBuilder idList = new StringBuilder()
for (int id : myArr) {
if (idList.length() > 0) {
idList.append(",");
}
idList.append(id);
}
Statement stmt = con.createStatement();
stmt.executeQuery("SELECT MESE,IMPORTO,ANNO FROM VISTASTATISTICHEMENSILI WHERE ANNO in("+idList+");
There is no issue with injection because the integers can't possibly have injected characters (if they did, they wouldn't be integers)
Try binding n integers manually inside for loop.
Before that you should create ?,?,...,? pattern in sql.
Good luck.
import org.apache.commons.lang3.StringUtils;
/*
* example: for n=4 creates pattern: ?,?,?,?
*/
public String createInListPattern(int n) {
return StringUtils.repeat("?", ",", n);
}
public void doSelect(Integer[] myArr, Connection conn) {
int size = myArr.length;
String sql = "SELECT MESE,... FROM TABLE WHERE ANNO in ("
+ createInListPattern(size) + ")";
// be sure to properly handle sql exceptions
PreparedStatement stmt = conn.prepareStatement(sql);
// bind parameters
for (int i = 0; i < size; i++) {
stmt.setInt(i + 1, myArr[i]);
}
// execute query
ResultSet rs = stmt.executeQuery();
}