2010-05-07 100 views
5

我有一个名为的JPA 2实体手术。它有一个成员transfusionUnits这是一个整数JPQL平均聚合函数是否与整数一起使用?

数据库中有两个条目。执行此JPQL声明:

Select s.transfusionUnits from Surgery s 

产生预期的结果:

2 
3 

下面的语句产生的预期的答案:

Select sum(s.transfusionUnits) from Surgery s 

我期待下面的答案声明为2.5,但它返回2.0代替

Select avg(s.transfusionUnits) from Surgery s 

如果我在不同的(Float)成员上执行语句,结果是正确的。任何想法为什么发生这种情况?我需要在JPQL中进行某种类型的演员吗?这甚至有可能吗?当然,我错过了一些微不足道的东西。

回答

7

首先,让我总结JPA 2.0规范说的话有关AVG(参见4.8.5 聚合函数在SELECT子句的全部内容)

的AVG函数接受的状态字段路径表达式作为参数并计算组中的状态字段的平均值。状态字段必须是数字,并且结果以Double形式返回。

所以,第一读取之后,我期待下面的代码片段经过:

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()); 

更新:看来,一些数据库(如MySQL的)就返回在INT列上使用AVG时有一个小数部分的值(这是有道理的,无论这里使用的数据库的文档行为如何)。对于其他数据库,可以在“方言”中处理 (例如,参见Hibernate的HHH-5173),以避免在使用JPQL时数据库之间的可移植性问题。

1

将平均场增加两倍的技巧。不知道性能影响,但不应该是什么邪恶的:但不应该是任何邪恶:

Select avg(s.transfusionUnits + 0.0) from Surgery s 
+0

它不适用于我,我得到的错误应该是)而不是+符号。 – 2015-07-20 19:31:58

+0

为openjpa工作,似乎它是提供程序依赖 – MarianP 2015-07-21 08:19:04