我正在尝试执行类似以下的查询,通过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
使用JPA 2.0 Criteria API和Hibernate。
我的测试用例看起来像......
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()
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
调用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]
我尝试按表达式分组的方式有问题吗?我还尝试按别名和数字文字(1,2)
进行分组我可以采用另一种方法来构建SQL以获得相同的结果吗?
感谢。
答案 0 :(得分:1)
正如异常消息所暗示的那样,问题与DBMS级别的Group By
语句有关。参见:https://www.percona.com/blog/2019/05/13/solve-query-failures-regarding-only_full_group_by-sql-mode/
要解决该错误,您必须
将基础DBMS的Group By Mode
设置为较少限制的级别(MySQL允许disable only-full-group-by,但H2 does not(您可以尝试在jdbc中设置MODE=MYSQL
连接字符串)
或(更好)
将属于select语句的所有列添加到GROUP BY
语句或above中所述的聚合函数中。
您应该能够构建满足GROUP BY RESTRICTIONS的嵌套查询。
为进行救援,有一些(也许是特定于DBMS的)汇总 功能(至少在MySQL中)。为了欺骗JPA和Hibernate理解这些内容,有 实现此目的的几种方法,如 https://vladmihalcea.com/hibernate-sql-function-jpql-criteria-api-query/ 和 https://vladmihalcea.com/the-jpa-entitymanager-createnativequery-is-a-magic-wand/
修改
除上述陈述外,下面讨论之后的发现是:
org.h2.expression.ExpressionColumn
类中引发了异常,它正在验证查询语法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();