Spring+Java8+Hibernate+MySQL应用中JPQL的SUM(CASE WHEN)语句始终返回0的问题排查
首先,从你描述的情况来看,核心矛盾点在于:JPQL中的CASE判断逻辑被Hibernate翻译成了和你预期完全不同的SQL条件,这是导致SUM结果始终为0的关键原因。
从你提供的Hibernate生成的SQL可以看到,JPQL里的SUM(CASE WHEN rk.vevoiEntity IS NOT NULL THEN rk.mennyisegMe1 ELSE 0.0 END)被翻译成了:
sum(case when rak0_.szallitolevel_tetel_id is not null or rak0_.kimeno_tetel_id is not null or rak0_.vevoi_tetel_id<>0 then rak0_.mennyiseg_me_1 else 0 end)
这说明你的实体类RaktarkeszletEntity中的vevoiEntity字段不是简单映射到数据库的单个字段,而是一个复合属性(比如用了@Formula注解组合了多个字段的判断),或者字段映射存在错误。
可能的原因与解决步骤
1. 检查实体类中vevoiEntity的映射定义
这是最关键的一步:
如果
vevoiEntity应该直接映射到数据库的vevoi_tetel_id字段(int类型,允许null),那么实体类中应该用Integer类型(而非基本类型int)来接收null值:@Column(name = "vevoi_tetel_id") private Integer vevoiEntity; // 用Integer,不要用int基本类型
int无法存储null,Hibernate会自动将数据库中的null转换为0,导致IS NOT NULL判断完全失效。如果
vevoiEntity是用@Formula定义的复合逻辑(比如判断多个字段是否非空),那你需要重新审视这个逻辑是否符合你的需求。比如如果原Formula是:@Formula("szallitolevel_tetel_id IS NOT NULL OR kimeno_tetel_id IS NOT NULL OR vevoi_tetel_id <> 0") private Boolean vevoiEntity;那JPQL中的
rk.vevoiEntity IS NOT NULL其实是判断这个布尔值是否不为null(永远为true),这显然和你要统计vevoi_tetel_id非空的需求不符。这种情况下,你应该直接在JPQL里写你需要的判断逻辑,而不是依赖这个复合属性。
2. 修正JPQL中的CASE判断逻辑
根据你能正常运行的原生SQL,调整JPQL的条件,确保和原生逻辑一致:
- 如果你只需要判断
vevoi_tetel_id不为null,且实体类映射正确(用Integer类型),可以写成:SUM(CASE WHEN rk.vevoiEntity IS NOT NULL THEN rk.mennyisegMe1 ELSE 0.0 END) - 如果数据库中
vevoi_tetel_id的null值会被Hibernate转为0(比如用了int类型),则直接判断大于0:SUM(CASE WHEN rk.vevoiEntity > 0 THEN rk.mennyisegMe1 ELSE 0.0 END) - 也可以直接使用Hibernate支持的数据库函数来模拟原生SQL的
IFNULL逻辑:SUM(CASE WHEN FUNCTION('IFNULL', rk.vevoiEntity, 0) > 0 THEN rk.mennyisegMe1 ELSE 0.0 END)
3. 修复GROUP BY子句的不规范问题
你的JPQL中存在一个不符合JPA规范的写法:SELECT中包含了未聚合且未在GROUP BY中的字段rk.mennyisegMe1*rk.listaar。虽然MySQL的宽松模式允许这种写法,但可能导致查询结果不稳定,甚至间接影响SUM的计算。建议修改为聚合形式,比如:
CONCAT(SUM(rk.mennyisegMe1*rk.listaar), ' Ft')
或者将相关字段加入GROUP BY(但这会改变分组逻辑,需要根据业务需求判断)。
4. 验证Hibernate生成的SQL
修改后再次开启hibernate.show_sql=true,确认生成的SQL中的CASE条件和你在Workbench中运行的原生SQL一致。比如应该生成类似:
sum(case when rak0_.vevoi_tetel_id is not null then rak0_.mennyiseg_me_1 else 0 end)
如果生成的SQL正确,那么SUM结果应该就能正常统计了。
内容的提问来源于stack exchange,提问作者ehunvan

