In JDBC I can use question marks for query parameters, like this:
"SELECT * FROM users WHERE login = ?"
and then
ps.setString(1, "vasya");
But how can I query for list of logins:
"SELECT * FROM users WHERE login IN ?"
suppose, I have
List<String> logins = ...
What should I type there:
ps.setWhat(1, what);
I could rewrite query as:
"SELECT * FROM users WHERE login = ? OR login = ? OR login = ?"
and then call setString in loop, but I'd like to know if it is possible to pass a set of elements as single param in query.
Maybe there are vendor-specific extensions?
There are vendor specific ways to do that, therefore it would be good to know what database you use. I know solutions for PostgreSQL and H2. I implemented this feature in the H2 database, so that's what I know best:
H2 Database
PreparedStatement prep = conn.prepareStatement(
"select * from users where login in (select * from table(x int = ?))");
prep.setObject(1, new Object[] { "1", "2" });
ResultSet rs = prep.executeQuery();
PostgreSQL
WHERE login = ANY(?)
Then set the parameter to an array of values using PreparedStatement.setArray(..) (not setObject as for H2).
Look here for an overview of available options. As far as I can tell you, everyone is dynamically generating the necessary number of placeholder characters (with some optimizations).
There's a setArray method in PreparedStatement, but sometimes using it is not feasible. You might give it a try though.
If Spring's JDBCTemplate is an option, you could use automatic collection expansion as described here.
//---
String query = "SELECT * FROM users WHERE login = ?";
List<Login> list = new ArrayList<Login>();
Login login = null;
for(String param : conditions){
pStmt.setString(1,param);
rSet = pStmt.executeQuery();
if(rSet.next()){
login = new Login();
login.setName(rSet.getString(1));
list.add(login);
}
}
return list;
//---
conditions will be the list of item on basis of which you want to retrieve fields.
Related
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '#gmail.com' at line 1
I don't know where is the problem
public List<UserModel> listUser(String emailParam) throws SQLException {
List<UserModel> users = new ArrayList<>();
Connection conn = null;
PreparedStatement pre = null;
ResultSet rs = null;
// Get Connection
conn = dataSource.getConnection();
// fetch query
String fetchUser = "SELECT * FROM user WHERE email = " + emailParam;
pre = conn.prepareStatement(fetchUser);
// execute query
rs = pre.executeQuery();
// fetch data using resultSet interface;
while (rs.next()) {
Integer id = rs.getInt("id");
String firstName = rs.getString("firstName");
...
String email = rs.getString("email");
Boolean isActive = rs.getBoolean("isActive");
Boolean isLibrarian = rs.getBoolean("isLibrarian");
// insert into user constructor
UserModel theUser = new UserModel(id, firstName, lastName, gender,
department, idNo, contactNo, address, email, null,
isLibrarian, isActive);
// insert into ArrayList
users.add(theUser);
}
// close connection
close(conn, pre, rs);
return users;
}
where is the problem Thanks in advance.
The error is here, in listUser():
// fetch query
String fetchUser = "SELECT * FROM user WHERE email = " + emailParam;
pre = conn.prepareStatement(fetchUser);
You managed to use a prepared statement when inserting the user, and you need to do the same here when querying:
// fetch query
String fetchUser = "SELECT * FROM user WHERE email = ?";
pre = conn.prepareStatement(fetchUser);
pre.setString(1, emailParam);
As a general thought, preparing statements has two main usages:
1) Minimise preparation time when executing a query
2) For security - among other things "query rewriting"
I also have an observation about a syntax error in your select at the bottom of this post.
If you are going to prepare statements, then it is better to do it once, then "remember" the preparedStatement that you get back. Do not prepare the same query over and over.
Most, if not all, DBMS's work as follows for prepared query processing:
1) you send the template query to the DBMS for parsing and optimisation. The output of this is known by a few different names, but for the purposes of this we can call this the "executable plan". This is the PrepareXXX call.
2) The DBMS remembers all of those details for the second stage i.e. when you send the data up as a result of the prepdQuery.executeQuery() (or similar) call. this has the effect of sending up the data and plugging it into the prepared query's executable plan.
This will always involve two network trips (one to prepare and one to execute). However ....
... If you need to run the same query again with different data (e.g. a different email), just execute the second step - this bypasses the overheads associated with parsing and planning. Which will increase your throughput significantly - especially for single row operations such as the insert (and most likely the select) shown above.
The alternative is the string concatenation method which will always require parsing etc and execution - but at least it will be only one trip over the network. This works best for longer running queries (where parse time is insignificant compared to execution times) or where the query logic is dynamic (made up at run time based upon user input).
However, if you do send the query text concatenated with user input, make sure you address point 2 above (query rewriting).
Also, finally, your concatenated SQL is missing single quotes.
The query must look like this (the text must be quoted)
select ... from ... where email = 'email#domain.com';
Thus your concatenation must look like this:
String fetchUser = "SELECT * FROM user WHERE email = '" + emailParam + "'";
What is query rewriting? Imaging if the emailParam entered by the user looked like this:
emailParam = "'; delete from user all; select 'hello"
Try plugging that into your select BUT DO NOT RUN IT unless you have a backup copy of your users table (or you get lucky).
Also, note that you never put quote marks around the ? placeholders in prepared queries - even if the parameter is a text or date value.
I use prepared statements to read/write data in my DB (SQLite). In my table INVENTORY, there are records which have null value in the column paleta (the column is defined as VARCHAR in the table). I want to select these records and I tried:
sq = "SELECT * FROM INVENTORY WHERE paleta = ? AND product = ? AND lot = ?";
//...
stm = c.prepareStatement(sq);
stm.setNull(1, java.sql.Types.VARCHAR);
stm.setString(2, "theIdOftheProduct");
stm.setString(3, "theLotOftheProduct");
ResultSet rs = stm.executeQuery();
The above query doesn't return anything.. I removed the paleta = ? and I get the records I want.. How can I define the query like SELECT * FROM INVENTORY WHERE paleta is null etc.. using the query parameters?
What you are trying to do is equivalent to writing SELECT * FROM INVENTORY WHERE paleta = NULL ..., which doesn't work.
Since you are essentially searching for rows having a constant value in the paleta column (which happens to be NULL), you can eliminate the first query parameter and explicitly check for null:
sq = "SELECT * FROM INVENTORY WHERE paleta IS NULL AND product = ? AND lot = ?";
stm = c.prepareStatement(sq);
stm.setString(1, "theIdOftheProduct");
stm.setString(2, "theLotOftheProduct");
I found my answer in https://stackoverflow.com/a/4215618/1052284
You'll have to decide upon an unused value. I simply kept it at '' since I don't have empty values.
sq = "SELECT * FROM INVENTORY WHERE IFNULL(paleta, '') = ? AND product = ? AND lot = ?";
//...
stm = c.prepareStatement(sq);
stm.setString(1, ""); // '' for NULL, otherwise a specific value
stm.setString(2, "theIdOftheProduct");
stm.setString(3, "theLotOftheProduct");
But beware if you many queries, it's VERY slow. I clock in at about 4000 times slower, on average, than queries without IFNULL. ~50ms instead of microseconds.
I have query like
`Select * from Table1 where xyz in (List of String to be Supplied).
In my java code. I have a dao object in which I am calling this sql using jdbc template.
The method takes in a list of String and that needs to be supplied to this SQl. I have my row-mapper.
How to write the SQl and how to pass the list of variables?
My SQL will run on a Teradata Db.
Use a NamedParameterJdbcTemplate which, as the doc says:
It also allows for expanding a List of values to the appropriate number of placeholders.
So you just need
String sql = "select * from Table1 where xyz in :list";
// or String sql = "select * from Table1 where xyz in (:list)";
// I can't remember which one is right
Map parameters = new HashMap<String, Object>();
parameters.put("list", theListOfXyz);
List<Foo> result = template.query(sql, parameters, rowMapper);
Good Evening, I am curious if it is possible to make a WHERE-clause in a SQL statement which can show all records?
Below some explanation:
Random SQL Statement (Java)-(JSP example), Normal Situation
String SqlStatement = "SELECT * FROM table_example WHERE First_Col = '<%=passVar%>' ";
db.query(SqlStatement );
//........
//........
What if the passVar is 'ALL', and we need to prompt all the records out when passVar = All? I know I can do it with if-else and check if the passVar is "ALL" then query the without-WHERE statement to make it work..
**without-WHERE statement (Java)-(JSP example)**
if(<%=passVar%> == "ALL") {
SqlStatement = "SELECT * FROM table_example";
} else {
SqlStatement = "SELECT * FROM table_example WHERE First_Col = '<%=passVar%>' ";
}
but can I just code one SQL statement to make all the records prompt? Something like below:
(Java)-(JSP example)
String ShowAll = "";
if(<%=passVar%> == "ALL") {
ShowAll = *;
} else {
ShowAll = <%=passVar%>;
}
SqlStatement = "SELECT * FROM table_example WHERE First_Col = ShowAll ";
Try with WHERE 1=1::
Select * from myTable WHERE 1=1
This also works:
WHERE columnname LIKE '%'
Except for NULL values.
where 1=1 worked for me, Although where clause was being used all records were selected.
You can also try
SELECT * FROM Customers
WHERE CustomerID=CustomerID; /* query */
or
[any_column_name]=[column_name_in_LHL]
(LHL=left hand side.)
copy the query and
click here to try code
It would be better to differ the 2 situations and make 2 queries out of it.
If there is no where condition then the DB does not need to evaluate it (potencially faster)
The source code/debugging output is clearer.
Consider moving the special case inside the query itself, e.g.
SELECT * FROM table_example WHERE '<%=passVar%>' IN ('ALL', First_Col)
Try with wildcard value '%' but I would recommend to use a Factory here to create the SQL statement, what you are trying to do smells a bit.
Something else you could do, is making that combination of code and SQL a single query. Which means the IF..ELSE will be in SQL language.
Check these links for some more info:
MySQL
Using If else in SQL Select statement
On sqlserver you can make proc:
create proc select_all_on_null
#a int
as
begin
select * from Records where (#a is null or Record_id=#a )
end
When you select be your program:
make #a in null will select all
if i is numder there will select row with this id
I’m using the following code to generate a search results from a relational DB, depending on the multiple (Optional) search parameters from the web based client.
Presently I’m using “java.sql.Statement” to achieve the functionality but I need the same to be achieved using “java.sql.PreparedStatement” in order to prevent SQL injections.
Let me know a best practice to change the code
E.g.
User inputs from web based client.
param1 - Optional
param2 - Optional
dateParamFr - Optional
dateParamTo - Optional
Pseudo code of SQL patterns depending on the search parameters as follows
IF (WITHOUT ANY SEARCH PARAMETER){
SELECT * FROM TEST_TABLE;
}
ELSE IF(WITH param1){
SELECT * FROM TEST_TABLE WHERE COLUMN1= param1;
}
ELSE IF(WITH param1 & param2){
SELECT * FROM TEST_TABLE WHERE COLUMN1= param1 AND COLUMN2= param2
}
SO ON
………
Following is the fragment of Java code in my EJB
/*
NOTE : Hashtable pSearchParam is a method parameter
*/
Connection cnBOP = null;
Statement stmt = null;
StringBuffer sb = new StringBuffer("");
try {
cnBOP = jdbcBOP.getConnection(); // DataSource jdbcBOP
stmt = cnBOP.createStatement();
/* ######################## SQL BODY ######################################*/
sb.append("SELECT COLUMN1, COLUMN2, DATE_COLUMN ");
sb.append("FROM TEST_TABLE ");
/* ######################## SQL WHERE CLAUSE ##############################*/
if(pSearchParam.size()>=1){
sb.append("WHERE ");
Enumeration e = pSearchParam.keys();
int count =0;
while(e.hasMoreElements()){
if (count >=1) sb.append("AND ");
String sKey = (String) e.nextElement();
if (sKey.equals("param1")) sb.append ("COLUMN1 ='"+pSearchParam.get(sKey)+"' ");
else if (sKey.equals("param1")) sb.append ("COLUMN2 ='"+pSearchParam.get(sKey)+"' ");
else if (sKey.equals("dateParamFr")) sb.append ("DATE_COLUMN >= TO_DATE('"+pSearchParam.get(sKey)+" 00:00:00','DD/MM/YYYY HH24:MI:SS') ");
else if (sKey.equals("dateParamTo")) sb.append ("DATE_COLUMN <= TO_DATE('"+pSearchParam.get(sKey)+" 23:59:59','DD/MM/YYYY HH24:MI:SS') ");
count ++;
}
}
/* ######################## SQL ORDER BY CLAUSE ############################*/
sb.append("ORDER BY DATE_COLUMN DESC");
ResultSet rs = stmt.executeQuery(sb.toString());
Instead of
sb.append ("COLUMN1 ='"+pSearchParam.get("param1")+"' ");
You will have to do
sb.append ("COLUMN1 = ? ");
and then after you create the statement you do
stmt.setString(1, pSearchParam.get("param1"));
This is only for the first parameter, you need to do this for all statements and enumerate the index in
setString(int index, String param);
Note that you will need to use other methods for int, long, Date... etc
Depend on your database engine you may use SQL functions like
isnull(value,valueIfNull)
for example in MSSQL
select * from Order where storeId = isnull(?,storeId)
next in you java code
preparedStatement.setNull(1,java.sql.Types.INTEGER)
if you need omit this param from filter or,
preparedStatement.setInt(1,20)
if you need find all orders with storeId = 20
This really looks like a job for Hibernate Criteria Queries...
Criteria is a simplified API for retrieving entities by composing
Criterion objects. This is a very
convenient approach for functionality
like "search" screens where there is a
variable number of conditions to be
placed upon the result set.
Are you using Hibernate? Then you can use the criteria API. Else for non hibernate you can take a look at the SqlBuilder tool to generate SQLs based on conditions.
Also you should use markers "?" instead of actual values.
So this query should be like this.
SELECT * FROM TEST_TABLE WHERE COLUMN1= ?;
You can then use PreparedStatements to set values for this column. An introductory tutorial on using PreparedStatement is here.