我有一个名为 Surgery 的JPA 2实体。它有一个名为 transfusionUnits 的成员,它是 Integer 。
数据库中有两个条目。执行这个JPQL语句:
Select s.transfusionUnits from Surgery s
产生预期结果:
2
3
以下语句产生 5 的预期答案:
Select sum(s.transfusionUnits) from Surgery s
我希望以下声明的答案为 2.5 ,但它会返回 2.0 。
Select avg(s.transfusionUnits) from Surgery s
如果我在另一个(Float)成员上执行语句,结果是正确的。有关为什么会发生这种情况的任何想法?我需要在JPQL中进行某种转换吗?这甚至可能吗?当然,我在这里错过了一些微不足道的东西。
答案 0 :(得分:9)
首先,让我总结一下JPA 2.0规范关于AVG的内容(请参阅 4.8.5 SELECT子句中的聚合函数部分了解完整内容)
AVG函数将状态字段路径表达式作为参数,并计算组上的状态字段的平均值。 state字段必须是数字,结果以double形式返回。
因此,在第一次阅读之后,我期待以下代码段传递:
Query q = em.createQuery("select avg(s.transfusionUnits) from Surgery s");
Double actual = (Double) q.getSingleResult();
assertEquals(2.5d, actual.doubleValue());
但事实并非如此,我得到2.0
作为结果(Double,但不是预期的结果)。
所以我查看了数据库级别并意识到SQL查询实际上没有返回2.5
。事实上,这就是我的数据库文档中关于AVG的内容:
平均值(平均值)。如果未选择任何行,则结果为NULL。仅在select语句中允许聚合。 返回的值与参数具有相同的数据类型。
我期待太多了。 JPA会将结果作为Double返回,但它不会做任何魔术。如果查询未返回具有所需精度的结果,则不会在Java级别获取它。
因此,在不更改transfusionUnits
的类型的情况下,我必须运行此本机查询才能使事情正常运行:
Query q = em.createNativeQuery("SELECT AVG(CAST(s.transfusionUnits as double)) from Surgery s");
Double actual = (Double) q.getSingleResult();
assertEquals(2.5d, actual.doubleValue());
更新:在INT列上使用AVG时,似乎某些数据库(例如MySQL)会返回带小数部分的值(这是有道理的,无论数据库记录的行为如何I在这里使用)。对于其他数据库,可以处理上述演员表 在“方言”(例如,参见H HHH-5173 for Hibernate)中,以避免在使用JPQL时数据库之间的可移植性问题。
答案 1 :(得分:1)
将平均字段转换为double可以解决问题。不确定性能影响,但不应该是邪恶的:
Select avg(s.transfusionUnits + 0.0) from Surgery s