5

我有一个名为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

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

4

2 回答 2

10

首先,让我总结一下 JPA 2.0 规范对 AVG 的规定(完整内容请参见SELECT 子句中的 4.8.5 聚合函数部分)

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了结果(双倍,但不是预期的结果)。

所以我查看了数据库级别,意识到 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());

更新:似乎某些数据库(例如 MySQL)在 INT 列上使用 AVG 时确实返回了一个带小数部分的值(这是有道理的,无论我在这里使用的数据库的记录行为如何)。对于其他数据库,可以在“方言”中处理上述转换(例如,请参阅Hibernate的 HHH-5173)以避免使用 JPQL 时数据库之间的可移植性问题。

于 2010-05-07T21:42:17.893 回答
1

将平均场加倍就可以了。不确定性能影响,但不应该是邪恶的:

Select avg(s.transfusionUnits + 0.0) from Surgery s
于 2011-02-09T15:36:15.740 回答