Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HOW to use HAVING COUNT(*) with hibernate

I need to create a query and I need COUNT(*) and HAVING COUNT(*) = x.

I'm using a work around that uses the CustomProjection class, that I downloaded somewhere.

This is the SQL that I try to achieve:

select count(*) as y0_, this_.ensayo_id as y1_ from Repeticiones this_
inner join Lineas linea1_ on this_.linea_id=linea1_.id
where this_.pesoKGHA>0.0 and this_.nroRepeticion=1 and linea1_.id in (18,24)
group by this_.ensayo_id
having count(*) = 2

This is the code, where I use the Projection Hibernate class:

critRepeticion.setProjection(Projections.projectionList()
                .add( Projections.groupProperty("ensayo") )
                .add( CustomProjections.groupByHaving("ensayo_id",Hibernate.LONG,"COUNT(ensayo_id) = "+String.valueOf(lineas.size()))
                .add( Projections.rowCount() )
                );

The error is:

!STACK 0
java.lang.NullPointerException
at org.hibernate.criterion.ProjectionList.toSqlString(ProjectionList.java:50)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getSelect(CriteriaQueryTranslator.java:310)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:71)
at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:67)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1550)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at ar.com.cse.cseagro.controller.RepeticionController.buscarEnsayo(RepeticionController.java:101)

If I comment the line with CustomProjections class, the query work, but I don't get the HAVING COUNT(*) filter in the SQL ...

Basically the query try to retrieve, in a master - detail schema, all the master records where a list of details are simultaneously present, like if you want tho know "which invoices have both products, A and B".

That why if I got 3 items in the IN clause, I need to use HAVING COUNT = 3 clause.

Any idea or suggestion? Best regards,

like image 846
Nicolas400 Avatar asked Dec 22 '11 15:12

Nicolas400


People also ask

What is the description for count () in hibernate?

The count() can be used to count any kind of values, including the number of rows in the query result. avg(): calculates the average of given numeric arguments. count() including count(distinct), count(all), and count(*): count the number of values/rows.

Can we use group by in HQL?

The HQL Group By clause is used to group the data from the multiple records based on one or more column. It is generally used in conjunction with the aggregate functions (like SUM, COUNT, MIN, MAX and AVG) to perform an aggregation over each group.


3 Answers

I figured out the problem. I replace CusotmProjections class, with:

.add( Projections.sqlGroupProjection("ensayo_id", groupBy , alias, types));

where groupBy, alias and types are:

 String groupBy = "ensayo_id" + " having " + "count(*) = " + String.valueOf(lineas.size());
 String[] alias = new String[1]; 
 Alias[0] = "ensayo_id"; 
 Type[] types = new Type[1]; 
 types[0] = Hibernate.INTEGER;

and the magic is on groupby String. –

like image 154
Nicolas400 Avatar answered Oct 04 '22 10:10

Nicolas400


If someone needs to do it in grails it would be like:

projections {
    groupProperty("id")
    sqlGroupProjection(...)
    rowCount()
}

Where sqlGroupProjection is available since 2.2.0

/**
 * Adds a sql projection to the criteria
 * 
 * @param sql SQL projecting
 * @param groupBy group by clause
 * @param columnAliases List of column aliases for the projected values
 * @param types List of types for the projected values
 */
protected void sqlGroupProjection(String sql, String groupBy, List<String> columnAliases, List<Type> types) {
    projectionList.add(Projections.sqlGroupProjection(sql, groupBy, columnAliases.toArray(new String[columnAliases.size()]), types.toArray(new Type[types.size()])));
}

http://grepcode.com/file/repo1.maven.org/maven2/org.grails/grails-hibernate/2.2.0/grails/orm/HibernateCriteriaBuilder.java/#267

like image 27
Milev Avatar answered Oct 04 '22 11:10

Milev


Here is my sample, it works fine, maybe useful :

My sql query :

select COLUMN1, sum(COLUMN2) from MY_TABLE group by COLUMN1 having sum(COLUMN2) > 1000;

And Criteria would be :

 Criteria criteria = getCurrentSession().createCriteria(MyTable.Class);
  ProjectionList projectionList = Projections.projectionList();
  projectionList.add(Projections.property("column1"), "column1");
  projectionList.add(Projections.sqlGroupProjection("sum(column2)  sumColumn2 ", "COLUMN1 having sum(COLUMN2) > 1000" , new String[]{"sumColumn2"}, new org.hibernate.type.Type[]{StandardBasicTypes.STRING}));
  criteria.setProjection(projectionList);
  criteria.List();
like image 43
Pasha GR Avatar answered Oct 04 '22 10:10

Pasha GR