In Simple JDBC (with no Hibernate)
we can do batch select by changing only place holder, like this
PreparedStatement stmt = conn.prepareStatement(
"select id, name from users where id = ?");
for ( int i=0; i < 10; i++ ) {
stmt.setInt(i); // or whatever values you are trying to query by
// execute statement and get result
}
How we can do it in Hibernate?
Hope this helps you out,
String hql = "from Users s where s.id= :userId";
for(int i=0; i< 10;i++){
List result = session.createQuery(hql)
.setParameter("userId", i)
.list();
}
This is the most common and user friendly way. It use colon followed by a parameter name (:example) to define a named parameter
Example 1: Using setParameter() method
String hql = "from Student s where s.registerNumner = :registerNumner";
List result = session.createQuery(hql).setParameter("registerNumner", "12345").list();
The setParameter() method is smart enough to discover the parameter data type of bind variable.
Example 2: Using setString() method
You can use setString to tell Hibernate this parameter date type is String.
String hql = "from Student s where s.registerNumber = :registerNumber";
List result = session.createQuery(hql).setString("registerNumber", "12345").list();
Example 3: Using setProperties() method
This feature is great ! You can pass an object into the parameter binding. Hibernate will automatic check the object’s properties and match with the colon parameter.
Student student = new Student();
Student.setRegisterNumber("12345");
String hql = "from Strudent s where s.registerNumber = :registerNumber";
List result = session.createQuery(hql).setProperties(student).list();
Example 4:
You can use positional parameters also.
String hql = "from Student s where s.registerNumber = ? and s.studentName = ?";
List result = session.createQuery(hql).setString(0, "12345").setParameter(1, "Harshad").list();
But it’s vulnerable to easy breakage because every change of the position(i.e. index) of the bind parameters requires a change to the parameter binding code
Batch select:
You can use following way for batch select
String hql = "from Users s where s.id= :userId";
List finalResult = new ArrayList();
for(int i=0; i< 10;i++){
List result = session.createQuery(hql).setParameter("userId", i).list();
finalResult.addCollection(result );
}
Related
I have a List<String> of categories and for each category, I want to add them to my WHERE clause by combining with AND operator like: SELECT question_id FROM question WHERE category = categ1 AND category = categ2 AND category = ...
Since the size of the categories list is changing, I cannot do something like this:
String sql = "SELECT question_id FROM question WHERE category = ? AND category = ?";
jdbcTemplate.query(sql, stringMapper, "categ1", "categ2");
How can I achieve what I want?
Either check if JDBC Template from Spring handle that for you using a syntax which could be something like (from the doc, I don't think it does)
SELECT question_id FROM question WHERE category in (?...)
Or write your own query with the problems that may arise:
List<Object> parameters = new ArrayList<>(categories.size());
StringBuilder sb = new StringBuilde("SELECT question_id FROM question WHERE 1=1");
if (!categories.isEmpty()) {
if (categories.size() == 1) {
sb.append(" and category = ?");
} else {
sb.append(" and category in ");
sb.append(categories.stream()
.map(ignored -> "?")
.collect(joining(", ", "(", ")")));
sb.append(")");
}
parameters.addAll(categories);
}
Object[] paramArray = parameters.toArray();
jdbcTemplate.query(sb.toString(), stringMapper, paramArray);
Notes:
some security/quality tool may report SQL issues because you are writing a dynamic SQL.
Oracle put a limit on 1000 elements per IN. You would have to partition categories per group of 1000 (or less).
I used a stream() in a more or less strange fashion in order to generate the "?". If you use commons-lang3, you can replace it by "(" + StringUtils.repeat("?", ", ", categories.size()) + ")" (the example in the javadoc was probably done with this kind of use).
if you only have category as single criteria, you may probably remove the 1=1 as well as the and.
I believe this may work for you:
// The SQL Query
String sql = "SELECT question_id FROM question";
// Create the WHERE clause based on the number of items in List...
StringBuilder whereClause = new StringBuilder(" WHERE ");
StringBuilder ps = new StringBuilder("");
for (int i = 0; i < categories.size(); i++) {
if (!ps.toString().isEmpty()) {
ps.append(" AND ");
}
ps.append("category = ?");
}
whereClause.append(ps.toString()).append(";");
//Append the WHERE clause string to the SQL query string
sql = sql + whereClause.toString();
//System.out.println(sql);
/* Convert the categories List to an Object[] Array so as to
pass in as varArgs to the jdbcTemplate.query() method. */
Object[] psArgs = categories.toArray(new Object[categories.size()]);
jdbcTemplate.query(sql, stringMapper, psArgs);
I have the following DAO method:
public String getSomeTable(final String param1) {
String sqlString = "select * from table where name ilike ?";
Query query = this.getEntityManager().createNativeQuery(sqlString);
query.setParameter(1, "%param1%");
}
If param1 is null or empty then I want to select all entries from the table. What is the correct way to do this? I am currently using the following:
public String getSomeTable(final String param1) {
String sqlString = "select * from table where name = ?";
Query query = this.getEntityManager().createNativeQuery(sqlString);
if(param1 == null)
query.setParameter(1, "%%");
else
query.setParameter(1, "%param1%");
}
But this is not scalable. I have datatypes like integer, date, etc. I want to know if there is a way to skip checking for that parameter if it is null.
I was planning to use COALESCE(?, CASE WHEN ? = '' THEN '%%' ELSE '%?%') but I think ? can be used only once for a particular parameter. The next one > I write is linked to second param.
On SQL Server, I use something like this, perhaps you can translate it to postgres:
DECLARE #variable INT = NULL;
SELECT *
FROM sysobjects
WHERE
(1 = CASE WHEN #variable IS NULL THEN 1 ELSE 2 END)
OR
(id LIKE #variable);
How I can make one dynamic query in Spring MVC with all my all my parameters from URL?
For exemple:/example?parameter1=test¶meter2=apple;fruit¶meter3=Park
For that link I want to have a query like that: SELECT * FROM news WHERE parameter1 = test AND parameter2 = apple AND fruits AND parameter3 = Park
In in the same time if I have a URL like that /example?parameter1=test¶meter2=apple
I don't want to create a new query in some one like SELECT * FROM news WHERE parameter1 = test AND parameter2 = apple;
More exactly, how can I create a dynamic query how change automatic in function of parameters from URL?
Its not good idea to pass dynamic data to query which will surely cause you SQL injection attacks.
You can use BeanPropRowMapper (http://www.mkyong.com/spring/spring-jdbctemplate-querying-examples/) and prepared statement kind of approach (Named parameters http://www.studytrails.com/frameworks/spring/spring-jdbc-template-named-params.jsp) in Spring JDBC to achieve similar but typed query. ( Your Java Bean getter and setter are automatically called, query is updated from that)
Don't write dynamic query ( keep it strict typed)
Check this if you can use it..
public StringBuilder prepareQuery(String tblName, String url)
{
StringBuilder query = new StringBuilder("Select * from " + tblName + " Where ");
String[] params = url.split("&");
for (int i = 0; i < params.length; i++ )
{
String str = params[i];
System.out.println(str.contains(";"));
if (i == 0)
{
query.append(str.replaceAll(";", " AND "));
}
else
{
query.append(" AND " + str.replaceAll(";", " AND "));
}
}
return query;
}
Given that my native SQL query returns a single non-null result, can somebody help me evaluate using query.getSingleResult() vs using query.getResultList.get(0)
Just for example:
String queryStr = "Select count(id) FROM Job J where companyMaster = 3";
Query query = getEntityManager().createNativeQuery(queryStr);
return ((BigInteger) query.getResultList().get(0)).intValue();
produces the same result as:
String queryStr = "Select count(id) FROM Job Jo where companyMaster = 3";
Query query = getEntityManager().createNativeQuery(queryStr);
return ((BigInteger) query.getSingleResult()).intValue();
If you are using database method like getById then it is okay to use the getSingleResult method. In this case, you are sure that there is only one entity in the database matching that id.
But as you are performing a count, you should use the getSingleResult as it almost definitely will return you a result rather than using getResultList.get(0).
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.