首先,让我总结一下 JPA 2.0 规范对 AVG 的规定(完整内容请参见 4.8.5 SELECT 子句中的聚合函数部分)
AVG 函数将状态字段路径表达式作为参数,并计算组中状态字段的平均值。 state 字段必须是数字,结果以 Double 形式返回。
所以,在第一次阅读之后,我期待以下 sn-p 通过:
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());
更新:似乎某些数据库(例如 MySQL)在 INT 列上使用 AVG 时确实返回了一个带小数部分的值(这是有道理的,无论我记录的数据库行为如何)此处使用)。对于其他数据库,可以处理上述演员表
在“方言”中(例如,Hibernate 参见 HHH-5173)以避免使用 JPQL 时数据库之间的可移植性问题。