简体   繁体   English

如何使用JPA Criteria API / Hibernate按Case语句进行分组

[英]How to group by Case statement using JPA Criteria API / Hibernate

I am trying to perform a query like the following, with selecting by a case statement and grouping by the same case statement.. 我正在尝试执行如下所示的查询,通过case语句进行选择并按相同的case语句进行分组。

Select USER, 
  (CASE
    WHEN value between 0 AND 2 then '0-2'
    WHEN value between 3 AND 4 then '3-4'
    ELSE '5+'
  END) as CASE_STATEMENT ,
SUM(value)
.....
Group by user, CASE_STATEMENT

using JPA 2.0 Criteria API, with Hibernate. 使用JPA 2.0 Criteria API和Hibernate。

My test case looks like ... 我的测试用例看起来像......

    CriteriaBuilder cb = em.getCriteriaBuilder()
    CriteriaQuery cq = cb.createQuery(Tuple)
    def root = cq.from(TestEntity)
    def userGet = root.get('user')
    def valueGet = root.get('value')
    def caseExpr =
            cb.selectCase()
                .when(cb.between(valueGet, 0, 2), '0-2')
                .when(cb.between(valueGet, 3, 4), '3-4')
                .otherwise('5+')
    def sumExpr = cb.sum(valueGet)

    cq.multiselect([userGet, caseExpr, sumExpr])
    cq.groupBy([userGet, caseExpr])
    log(typedQuery.unwrap(Query).queryString)
    List<Tuple> tuples = typedQuery.getResultList()

The log statement of the queryString reads queryString的日志语句读取

SELECT generatedAlias0.USER, 
   CASE 
     WHEN generatedAlias0.value BETWEEN 0 AND 2 THEN Cast(:param0 AS STRING) 
     WHEN generatedAlias0.value BETWEEN 3 AND 4 THEN Cast(:param1 AS STRING) 
     ELSE Cast(:param2 AS STRING) 
   END, 
   Sum(generatedAlias0.value) 
FROM   test AS generatedAlias0 
GROUP  BY generatedAlias0.USER, 
      CASE 
        WHEN generatedAlias0.value BETWEEN 0 AND 2 THEN Cast( 
        :param3 AS STRING) 
        WHEN generatedAlias0.value BETWEEN 3 AND 4 THEN Cast( 
        :param4 AS STRING) 
        ELSE Cast(:param5 AS STRING) 
      END 

When calling the typedQuery.getResultList(), I get the following error statement 调用typedQuery.getResultList()时,我得到以下错误语句

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not extract ResultSet

Caused by: org.h2.jdbc.JdbcSQLException: Column "TESTENTITY0_.VALUE" must be in the GROUP BY list; SQL statement:

select testentity0_.user as col_0_0_, case when testentity0_.value between 0 and 2 then cast(? as varchar(255)) when testentity0_.value between 3 and 4 then cast(? as varchar(255)) else cast(? as varchar(255)) end as col_1_0_, sum(testentity0_.value) as col_2_0_ from test testentity0_ group by testentity0_.user , case when testentity0_.value between 0 and 2 then cast(? as varchar(255)) when testentity0_.value between 3 and 4 then cast(? as varchar(255)) else cast(? as varchar(255)) end [90016-194]

Is there something wrong with the way I am trying to group by the Expression? 我试图通过表达式分组的方式有什么问题吗? I have also tried grouping by alias names, and by number literals (1, 2) 我也尝试按别名和数字文字分组(1,2)

Is there another way I can go about structuring the SQL to get the same results? 有没有其他方法可以构建SQL以获得相同的结果?

Thanks. 谢谢。

As the exception message suggests, the problem is related to the Group By statement at DBMS level. 正如异常消息所示,该问题与DBMS级别的Group By语句有关。 See: https://www.percona.com/blog/2019/05/13/solve-query-failures-regarding-only_full_group_by-sql-mode/ 请参阅: https//www.percona.com/blog/2019/05/13/solve-query-failures-regarding-only_full_group_by-sql-mode/

To solve the error, you must either 要解决错误,您必须要么

Edit 编辑

In contrast and addition to the statement above, the findings after discussion below are: 与上述陈述相反,经过以下讨论后的调查结果如下:

  • The exception is raised by the h2 driver in the org.h2.expression.ExpressionColumn class, while it's verifying the query syntax org.h2.expression.ExpressionColumn类中的h2驱动程序引发异常,同时验证查询语法
  • The solution requires setting and referencing an alias in the query (at the case statement or subquery ), which is currently not possible in Criteria API (see column aliases usually can't be referenced in the query itself ) 该解决方案需要在查询中设置和引用别名(在case语句子查询中 ),这在Criteria API中是不可能的(参见列别名通常不能在查询本身中引用
  • A workaround would be creating of a NativeQuery like this: 解决方法是创建一个这样的NativeQuery:
List<Tuple> tuples = em.createNativeQuery(
"SELECT generatedAlias0.USER, " +
"   CASE " +
"     WHEN generatedAlias0.value BETWEEN 0 AND 2 THEN Cast(:param0 AS VARCHAR) " +
"     WHEN generatedAlias0.value BETWEEN 3 AND 4 THEN Cast(:param1 AS VARCHAR) " +
"     ELSE Cast(:param2 AS VARCHAR) " +
"   END c, " +
"   Sum(generatedAlias0.value) as sumvalue " +
"FROM test AS generatedAlias0 " +
"GROUP  BY generatedAlias0.USER, c "
)
.setParameter("param0", "0-2")
.setParameter("param1", "3-4")
.setParameter("param2", "5+")
.getResultList();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM