SQL-запрос выдает исключение «не в агрегатной функции или в предложении группы по»
Вопрос
Я работаю над восстановлением набора тестов для нашего проекта, который тестируется через Hibernate/DBUnit.Есть несколько тестовых случаев, которые выдают похожее исключение из Hibernate, которое выглядит примерно так:
java.sql.SQLИсключение:Не в агрегатной функции или группе по предложению:org.hsqldb.Expression@109062e в заявлении [...бла...]
Погуглив, я подозреваю, что это вызвано использованием агрегатной функции AVG(), поскольку она содержится в сообщении об исключении, и все выдающие запросы содержат ее.Однако я обнаружил несколько ссылок на людей, у которых возникла эта ошибка, и смог исправить ее, либо закомментировав предложение «ORDER BY» или «GROUP BY», либо включив в группировку другие столбцы из предложения SELECT.Я понимаю, почему это исправит такое сообщение об ошибке, но я не уверен, применимо ли это к моей ситуации, потому что я пробовал сделать то же самое, и это не имело никакого значения.Кроме того, у нас есть несколько тестовых примеров, выдающих исключения, которые используют ORDER/GROUP, но не все.Например:
ThingerVO myThinger = (ThingerVO)session.createQuery("SELECT new ThingerVO(" +
"r.id, " + "u.id, " + "u.alias, " + "s.id, " +
"s.name, " + "r.URL," + "AVG(v.rating), " +
"r.totalCount, " + "r.isPrivate, " + "a.id, " +
"a.name, " + "r.transactionId, " + "r.size, " +
"u.hasPicture " +
") FROM Thinger r LEFT OUTER JOIN r.votes as v, Table1S s " +
"JOIN s.Table2A AS a, User u " +
"WHERE r.userId = u.id AND " +
"s.id = r.Table1SId AND " +
"r.id = :thingId")
.setInteger("thingId", thingId)
.uniqueResult();
Этот запрос также вызывает то же исключение, даже если он не использует предложение ORDER/GROUP.Кроме того, я вырезал/вставил сгенерированный код HSQL из Hibernate непосредственно в браузер запросов MySQL, и он запустился без проблем.Кроме того, стоит отметить, что весь этот код отлично работает в нашей производственной базе данных, поэтому я очень не понимаю, почему он выдает это здесь.
Еще одна потенциально полезная информация: мы используем плоскую структуру базы данных XML с некоторыми фиктивными тестовыми данными для тестовых случаев и диалект MySQL для спящего режима.Мы используем dbunit 2.4.3/hibernate 3.2.6.Я попробовал использовать последнюю версию гибернации, версию 3.3.1, но она вела себя так же.
Любые указатели или подсказки будут очень признательны.
Решение
Если вы используете агрегатную функцию (например. AVG()
) в части SELECT SQL-запроса вместе с другими неагрегированными выражениями, то у вас должно быть предложение GROUP BY, в котором должны быть перечислены все неагрегированные выражения.
Я не знаком с Java, но, глядя на код, кажется, что он собирается создать и выполнить запрос примерно так (не совсем правильно, но, я думаю, достаточно близко):
SELECT r.id,
u.id,
u.alias,
s.id,
s.name,
r.URL,
AVG(v.rating),
r.totalCount,
r.isPrivate,
a.id,
a.name,
r.transactionId,
r.size,
u.hasPicture
FROM Thinger r
LEFT OUTER JOIN r.votes as v,
Table1S s
JOIN s.Table2A AS a, User u
WHERE r.userId = u.id
AND s.id = r.Table1SId
AND r.id = :thingId
...Это не имеет GROUP BY
, но смешивает агрегатные и неагрегированные выражения в предложении SELECT.Проблема в том, что SQL плохо сформирован.
Исправлением будет добавление GROUP BY
до конца запроса.
Я не могу сказать, почему это работает в вашей производственной системе, но подозреваю, что здесь есть некоторая тонкая разница.Возможно, что-то добавляет GROUP BY
автоматически?
Можете ли вы опубликовать распечатку SQL, который он выполняет?
Другие советы
Также, ORDER BY
не работает в hsqldb, если поле порядка не является строкой.
К сожалению, это приводит к Не в агрегатной функции или группе по предложению сообщение об ошибке, которое предполагает проблему с группировкой, отсюда и путаница...
В некоторых системах (например, TALEND) запрос не работает, если есть строки комментариев. Пример:
SELECT r.id,
u.alias,
AVG(v.rating),
r.totalCount
FROM Thinger r
LEFT OUTER JOIN r.votes as v,
Table1S s
JOIN s.Table2A AS a, User u
WHERE r.userId = u.id
AND s.id = r.Table1SId
AND r.id = :thingId
--AND r.name is not null
GROUP BY r.id, u.alias, r.totalCount
Выдает ошибку для запросов MS SQL.Вместо строки комментария
--
используйте эти символы для комментариев
/* И r.name не равно нулю */
Возможно, кому-то это поможет и сэкономит время.