我有一个叫外科的JPA 2实体。它有一个名为transfusionUnits的成员,它是一个整数。
数据库中有两个条目。执行此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
如果我在另一个(浮动)成员上执行语句,则结果是正确的。对为什么会发生这种事有什么想法吗?我需要在JPQL中做一些演员吗?这有可能吗?当然,我错过了一些琐碎的东西。
发布于 2010-05-07 13:42:17
首先,让我总结一下JPA2.0规范对AVG的看法(有关全部内容,请参阅SELECT条款中的4.8.5节)
AVG函数以状态字段路径表达式作为参数,并计算组中sate字段的平均值。状态字段必须是数字字段,并且结果返回为双倍。
因此,在第一次阅读之后,我希望下面的片段能够通过:
Query q = em.createQuery("select avg(s.transfusionUnits) from Surgery s");
Double actual = (Double) q.getSingleResult();
assertEquals(2.5d, actual.doubleValue());
但它没有,我得到了2.0
作为结果(双倍,但不是预期的结果)。
因此,我查看了数据库级别,并意识到SQL查询实际上没有返回2.5
。事实上,这就是我的数据库中关于AVG的文档:
平均值(平均值)如果未选中任何行,则结果为NULL。只有在select语句中才允许聚合。返回的值与参数具有相同的数据类型。
我期待太多了。JPA将以双倍的形式返回结果,但它不会有任何魔力。如果查询没有以所需的精度返回结果,则无法在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)确实返回带有十进制部分的值(这是有意义的,而不管我在这里使用的数据库的记录行为如何)。对于其他数据库,上述转换可以用“方言”(例如,参见Hibernate的HHH-5173 )来处理,以避免使用JPQL时数据库之间的可移植性问题。
发布于 2011-02-09 07:36:15
将平均场转换为“加倍”就可以了。不确定对性能的影响,但不应该是什么坏事:
Select avg(s.transfusionUnits + 0.0) from Surgery s
https://stackoverflow.com/questions/2791378
复制