2
votes

I'm having some trouble with an sql query. I'm using Hibernate Criteria to build the query. I create some bins from a database by rounding the values with certain intervals (the binSize) and then grouping them. This works great when I try it directly in SQL with the query:

SELECT floor(phiTorsionAngle / 2) * 2 as phiTorsionAngleBin, 
       floor(psiTorsionAngle / 2) * 2 as psiTorsionAngleBin, 
       floor(phiTorsionAngle / 2) + 180 as phiTorsionAngleBinIndex, 
       floor(psiTorsionAngle / 2) + 180 as psiTorsionAngleBinIndex, 
       count(*) as numberOfResidues
FROM residue

WHERE phitorsionangle IS NOT NULL
  AND psitorsionangle IS NOT NULL

GROUP BY phiTorsionAngleBin, psiTorsionAngleBin

But when I try it with Hibernate Criteria it fails. This is the code to build the query:

ScrollableResults phiPsiBins = createCriteria()
.setProjection(Projections.projectionList()
       .add(Projections.sqlGroupProjection(
         "floor(phiTorsionAngle / " + binSize + ") * " + binSize + " as phiTorsionAngleBin, " +
         "floor(psiTorsionAngle / " + binSize + ") * " + binSize + " as psiTorsionAngleBin, " +         
         "floor(phiTorsionAngle / " + binSize + ") + 180 as phiTorsionAngleBinIndex, " +
         "floor(psiTorsionAngle / " + binSize + ") + 180 as psiTorsionAngleBinIndex, " + 
         "count(*) as numberOfResidues",
         "phiTorsionAngleBin, psiTorsionAngleBin",
         new String[] {"phiTorsionAngleBin", "psiTorsionAngleBin", "phiTorsionAngleBinIndex", "psiTorsionAngleBinIndex", "numberOfResidues"},
         new Type[] {Hibernate.DOUBLE, Hibernate.DOUBLE, Hibernate.INTEGER, Hibernate.INTEGER, Hibernate.INTEGER})))
.add(Restrictions.isNotNull("phiTorsionAngle"))
.add(Restrictions.isNotNull("psiTorsionAngle"))
.setResultTransformer(Transformers.aliasToBean(PhiPsiBinResult.class))
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);

This is the error message I'm getting, with the full stacktrace below it:

ERROR: column "this_.phitorsionangle" must appear in the GROUP BY clause or be used in an aggregate function

WARN  2011-01-11 16:13:43,047 main JDBCExceptionReporter:100 - SQL Error: 0, SQLState: 42803
ERROR 2011-01-11 16:13:43,047 main JDBCExceptionReporter:101 - ERROR: column "this_.phitorsionangle" must appear in the GROUP BY clause or be used in an aggregate function
  Position: 143
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute query using scroll
 at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:90)
 at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
 at org.hibernate.loader.Loader.scroll(Loader.java:2340)
 at org.hibernate.loader.criteria.CriteriaLoader.scroll(CriteriaLoader.java:113)
 at org.hibernate.impl.SessionImpl.scroll(SessionImpl.java:1561)
 at org.hibernate.impl.CriteriaImpl.scroll(CriteriaImpl.java:320)
 at nl.ru.cmbi.pdbeter.core.controller.DAO.ResidueDAO.getPhiPsiBinSet(ResidueDAO.java:236)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:616)
 at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
 at $Proxy27.getPhiPsiBinSet(Unknown Source)
 at nl.ru.cmbi.pdbeter.statistics.controller.StatisticsFunctions.makeRamachandranPlot(StatisticsFunctions.java:26)
 at nl.ru.cmbi.pdbeter.statistics.controller.StatisticsMain.start(StatisticsMain.java:39)
 at nl.ru.cmbi.pdbeter.statistics.controller.StatisticsMain.main(StatisticsMain.java:33)
Caused by: org.postgresql.util.PSQLException: ERROR: column "this_.phitorsionangle" must appear in the GROUP BY clause or be used in an aggregate function
  Position: 143
 at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2062)
 at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1795)
 at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
 at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:479)
 at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:367)
 at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:271)
 at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
 at org.hibernate.loader.Loader.getResultSet(Loader.java:1812)
 at org.hibernate.loader.Loader.scroll(Loader.java:2305)
 ... 18 more

I tried adding the phiTorsionAngle and psiTorsionAngle to the GROUP BY, and this seems to work, but it makes no sense to do that. I don't want to group by every possible value for phiTorsionAngle, I want to group by the entire bin, probably containing a lot of different values for phiTorsionAngle. Why does it give me this error and how do I work around it?

UPDATE: I didn't actually try to let the query run until it was finished yet, and I got a Java out of heap space error, because it tried to load about 19 million entries, so adding the phiTorsionAngle and psiTorsionAngle to the grouping is now entirely out of the question :)

1

1 Answers

1
votes
SELECT  phiTorsionAngleHalfFloor * 2 as phiTorsionAngleBin, 
        psiTorsionAngleHalfFloor * 2 as psiTorsionAngleBin, 
        phiTorsionAngleHalfFloor + 180 as phiTorsionAngleBinIndex, 
        psiTorsionAngleHalfFloor + 180 as psiTorsionAngleBinIndex, 
        numberOfResidues
FROM    (
        SELECT  FLOOR(phiTorsionAngleHalf / 2) AS phiTorsionAngleHalfFloor,
                FLOOR(psiTorsionAngleHalf / 2) AS psiTorsionAngleHalfFloor,
                COUNT(*) AS numberOfResidues
        FROM    residue
        WHERE   phitorsionangle IS NOT NULL
                AND psitorsionangle IS NOT NULL
        GROUP BY
                phiTorsionAngleHalfFloor, psiTorsionAngleHalfFloor
        ) q