Hi i need to dynamically build a query based on user selection. I cant write where conditions with if statement because i have 50 columns in table.is there a way without if statements?
You can look on CrtitriaAPI or you can use hibernate feature
Query by example
Actually if you are using spring with spring data module you can look into Specifications
Please look into below links:
https://dzone.com/articles/hibernate-query-example-qbe
https://vladmihalcea.com/query-entity-type-jpa-criteria-api/
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
Do you mean how to avoid the sql injection like concatenating sql statements at runtime?
static final String INVOICE_QUERY = "SELECT inv from Invoice inv WHERE (:createDate IS NULL OR inv.createDate = :createDate) AND (:quantity IS NULL OR inv.quantity = :quantity) AND (:custName IS NULL OR inv.custName = :custName)";
Session session = getHibernateTemplate().getSessionFactory().openSession();
Query query = session.createQuery(INVOICE_QUERY);
query.setDate("createDate", createDate);
if(quantity != null)
query.setLong("quantity", quantity);
else
query.setBigInteger("quantity", null);
if(StringUtils.isNotBlank(custName))
query.setString("custName", custName);
else
query.setString("custName", null);
return query.list();
Related
I am trying to implement a functionality where I have to query a database with input parameter values. Input values are optional.
For example
I have a table student with following fields
a)student_id
b)student_roll_no
c)student_first_name
d)student_last_name .. etc
I am need to write a dao layer function so as to retrieve student details depending upon input criteria or parameters.
1) if Input contains only student_id then query should be
select * from student where student_id = :inputStudentId
2) if Input contains student_id, firstName then query should be
select * from student where student_id = :inputStudentId and first_name = :inputFirstName
like wise for other input parameters, please note input parameters can be 0 to n size
Please suggest what is the best approach to do it?
I dont wann add null checks and append the query for not null parameters. I want to try something reasonable and logical either in Java or sql (named query)
I am using java1.6 and hibernate
If you using Hibernate, you can use HSQL to do that in following manner:
query=em.createQuery("SELECT s FROM Student s WHERE s.id=:id");
query.setParameter("id",studentIt)
For exact API details, check the documentation # http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html
You can also use CriteraApi - this is made for dynamic query creation.
You can do this by dynamically building your HQL with optional Parameters something like shown below:
Map<String, Object> parameters= new HashMap<String,Object>();
parameters.put("firstName", firstName);
parameters.put("lastName", lastName);
StringBuilder hql = "SELECT student FROM Student as student where 1 = 1";
if (firstName != null) {
hql.append(" and student.firstName in :firstName");
}
if (lastName != null) {
hql.append(" and student.lastName in :lastName ");
}
Query query = session.createQuery(hql.toString());
for (String p : query.getNamedParameters()) {
query.setParameter(p, parameters.get(p));
}
I have this select in PostgreSQL:
SELECT "field_1", "field_2","field_3", MIN(COALESCE(NULLIF("field_4",'') ,'TBD')) MINDP,MIN("field_5") MINBOD FROM "MY_TABLE" GROUP BY "field_1", "field_2","field_3"
And I want to use net.java.ao.Query to query my database. My function:
import net.java.ao.Query;
public List<myClass> find() {
String SQL = "SELECT \"field_1\", \"field_2\",\"field_3\", MIN(COALESCE(NULLIF(\"field_4\",'') ,'TBD')) MINDP,MIN(\"field_5\") MINBOD FROM \"MY_TABLE\" GROUP BY \"field_1\", \"field_2\",\"field_3\""
return newArrayList(ao.find(myClass.class, Query.select(SQL)));
}
The problem is: this code return all issues of my table.
When I run this SQL in postgreSQL console it works fine.
My code has different results than SQL console.
Does anybody know why is this happening?
Old question but if somebody steps over this -
Query.select() is not meant to put plain SQL into. It is more of a builder to create 'database independant' query. See some examples here: Finding entities
public MyEntity[] findMyEntities(String fieldValue) {
final Query query = Query.select()
.where("FIELD_VALUE = ?", fieldValue);
// evaluates to something like this
// SELECT * FROM MY_ENTITY WHERE FIELD_VALUE = x;
return ao.find(MyEntity.class, query);
}
This is why there's another method (which you used in your comment), that can handle plain SQL (findWithSQL).
Attention Query and find() often do not work as expected, so you might not get your original query to work using the query builder.
I'm using an ebean query in the play! framework to find a list of records based on a distinct column. It seems like a pretty simple query but the problem is the ebean method setDistinct(true) isn't actually setting the query to distinct.
My query is:
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findList();
In my results I get duplicate artist names.
From what I've seen I believe this is the correct syntax but I could be wrong. I'd appreciate any help. Thank you.
I just faced the same issue out of the blue and can not figure it out. As hfs said its been fixed in a later version but if you are stuck for a while you can use
findSet()
So in your example use
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findSet();
According to issue #158: Add support for using setDistinct (by excluding id property from generated sql) on the Ebean bug tracker, the problem is that an ID column is added to the beginning of the select query implicitly. That makes the distinct keyword act on the ID column, which will always be distinct.
This is supposed to be fixed in Ebean 4.1.2.
As an alternative you can use a native SQL query (SqlQuery).
The mechanism is described here:
https://ebean-orm.github.io/apidocs/com/avaje/ebean/SqlQuery.html
This is from the documentation:
public interface SqlQuery
extends Serializable
Query object for performing native SQL queries that return SqlRow's.
Firstly note that you can use your own sql queries with entity beans by using the SqlSelect annotation. This should be your first approach when wanting to use your own SQL queries.
If ORM Mapping is too tight and constraining for your problem then SqlQuery could be a good approach.
The returned SqlRow objects are similar to a LinkedHashMap with some type conversion support added.
// its typically a good idea to use a named query
// and put the sql in the orm.xml instead of in your code
String sql = "select id, name from customer where name like :name and status_code = :status";
SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
sqlQuery.setParameter("name", "Acme%");
sqlQuery.setParameter("status", "ACTIVE");
// execute the query returning a List of MapBean objects
List<SqlRow> list = sqlQuery.findList();
i have a solution for it:-
RawSql rawSql = RawSqlBuilder
.parse("SELECT distinct CASE WHEN PARENT_EQUIPMENT_NUMBER IS NULL THEN EQUIPMENT_NUMBER ELSE PARENT_EQUIPMENT_NUMBER END AS PARENT_EQUIPMENT_NUMBER " +
"FROM TOOLS_DETAILS").create();
Query<ToolsDetail> query = Ebean.find(ToolsDetail.class);
ExpressionList<ToolsDetail> expressionList = query.setRawSql(rawSql).where();//ToolsDetail.find.where();
if (StringUtils.isNotBlank(sortBy)) {
if (StringUtils.isNotBlank(sortMode) && sortMode.equals("descending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
//expressionList.orderBy().asc(sortBy);
}else if (StringUtils.isNotBlank(sortMode) && sortMode.equals("ascending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"asc");
// expressionList.orderBy().asc(sortBy);
} else {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
}
}
if (StringUtils.isNotBlank(fullTextSearch)) {
fullTextSearch = fullTextSearch.replaceAll("\\*","%");
expressionList.disjunction()
.ilike("customerSerialNumber", fullTextSearch)
.ilike("organizationalReference", fullTextSearch)
.ilike("costCentre", fullTextSearch)
.ilike("inventoryKey", fullTextSearch)
.ilike("toolType", fullTextSearch);
}
//add filters for date range
String fromContractStartdate = Controller.request().getQueryString("fm_contract_start_date_from");
String toContractStartdate = Controller.request().getQueryString("fm_contract_start_date_to");
String fromContractEndtdate = Controller.request().getQueryString("fm_contract_end_date_from");
String toContractEnddate = Controller.request().getQueryString("fm_contract_end_date_to");
if(StringUtils.isNotBlank(fromContractStartdate) && StringUtils.isNotBlank(toContractStartdate))
{
Date fromSqlStartDate=new Date(AppUtils.convertStringToDate(fromContractStartdate).getTime());
Date toSqlStartDate=new Date(AppUtils.convertStringToDate(toContractStartdate).getTime());
expressionList.between("fmContractStartDate",fromSqlStartDate,toSqlStartDate);
}if(StringUtils.isNotBlank(fromContractEndtdate) && StringUtils.isNotBlank(toContractEnddate))
{
Date fromSqlEndDate=new Date(AppUtils.convertStringToDate(fromContractEndtdate).getTime());
Date toSqlEndDate=new Date(AppUtils.convertStringToDate(toContractEnddate).getTime());
expressionList.between("fmContractEndDate",fromSqlEndDate,toSqlEndDate);
}
PagedList pagedList = ToolsQueryFilter.getFilter().applyFilters(expressionList).findPagedList(pageNo-1, pageSize);
ToolsListCount toolsListCount = new ToolsListCount();
toolsListCount.setList(pagedList.getList());
toolsListCount.setCount(pagedList.getTotalRowCount());
return toolsListCount;
i am new to this and today i tried to play hibernate with a method that returns the result of selected row...if is selected then it can return the result in int.. here is my method
public int validateSub(String slave, String source, String table){
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Query q = session.createQuery("from Subscribers where slave = :slave AND source = :source AND tbl = :tbl");
q.setParameter("slave", slave);
q.setParameter("source", source);
q.setParameter("tbl", table);
int result = q.executeUpdate();
return result;
}
from this method i tried to validate the 3 values that i get from the Subscribers table but at the end i tried to compile having this error
Exception in thread "Thread-0" org.hibernate.hql.QueryExecutionRequestException: Not supported for select queries [from com.datadistributor.main.Subscribers where slave = :slave AND source = :source AND tbl = :tbl]
You can have a look at the below links that how executeUpdate works, one is from the hibernate docs and other the java docs for JPA which defines when the exception is thrown by the method
http://docs.oracle.com/javaee/6/api/javax/persistence/Query.html#executeUpdate()
https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/Query.html#executeUpdate()
Alternatively you can use
List list = query.list();
int count = list != null ? list.size() : 0;
return count;
you are running a select query, Eventhough you are not using the select keyword here hibernate will add that as part of the generated SQL.
what you need to do to avoid the exception is the say
q.list();
now, this will return a List (here is the documentation).
if you are trying to get the size of the elements you can say
Query q = session.createQuery("select count(s) from Subscribers s where slave = :slave AND source = :source AND tbl = :tbl");
Long countOfRecords = (Long)q.list().get(0);
you can execute update statements as well in HQL, it follows a similar structure as SQL (except with object and properties).
Hope this helps.
here you want to select record so it is posible without select key word
sessionFactory sesionfatory;
ArrayList list = (ArrayList)sessionfactory.getCurruntSession().find(from table where name LIKE "xyz");
long size = list.get(0);
I also happened to make the same mistake today.
Your SQL statement is not correct.
You can try:
DELETE from Subscribers WHERE slave = :slave AND source
Try this:
int result = q.list().size();
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.