JPQL в среднем работа агрегатной функции с Целыми числами?

У меня есть объект 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? Это даже возможно? Конечно, я пропускаю что-то тривиальное здесь.

5
задан Pascal Thivent 7 May 2010 в 21:42
поделиться

1 ответ

Во-первых, позвольте мне резюмировать то, что спецификация 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 как результат (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) действительно возвращает значение с десятичной частью при использовании AVG в столбце INT (что имеет смысл, независимо от задокументированного поведения базы данных, которую я использовал здесь). Для других баз данных приведенное выше приведение может быть обработано на "диалекте" (например,см. HHH-5173 для Hibernate), чтобы избежать проблем с переносимостью между базами данных при использовании JPQL.

9
ответ дан 13 December 2019 в 22:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: