У меня есть следующие таблицы:
CREATE TABLE Rosters
(
id INTEGER NOT NULL,
club_abbr VARCHAR(10) NOT NULL,
ordinal_nbr SMALLINT,
PRIMARY KEY (id)
);
CREATE TABLE Games
(
id INTEGER NOT NULL,
scheduled_tipoff DATETIME NOT NULL,
PRIMARY KEY (id)
);
-- join table
CREATE TABLE Scores
(
game_id INTEGER NOT NULL,
is_home BOOLEAN NOT NULL,
roster_id INTEGER NOT NULL,
final_score SMALLINT DEFAULT NULL NULL,
PRIMARY KEY (game_id, is_home),
FOREIGN KEY (game_id) REFERENCES Games (id),
FOREIGN KEY (roster_id) REFERENCES Rosters (id)
);
Простая логика, игра имеет два счета, дома и в гостях (по is_home в PK), которые связаны с идентификатором реестра. Таблица результатов - это, в основном, таблица соединений между играми и списками. Я сопоставил классы соответственно (здесь нет проблем):
Вот данные, которые я хочу собрать далее (14 игр, 28 очков, 14 очков за [sf], 14 очков против [sa] и 2 пустых игры без игры):
|sf.roster.id|ga.id|sf.finalScore|sa.finalScore|
|------------|-----|-------------|-------------|
| 1| 3| null| null|
| 1| 5| 71| 93|
| 1| 11| 77| 80|
| 1| 13| 65| 71|
| 1| 16| 88| 90|
| 1| 22| 58| 51|
| 1| 23| 71| 75|
| 1| 30| null| null|
| 1| 32| 89| 86|
| 1| 40| 62| 71|
| 1| 42| 64| 60|
| 1| 46| 73| 101|
| 1| 48| 50| 43|
| 1| 51| 88| 60|
Сумма очков за 856, сумма очков против 881. 12 сыгранных игр. Средний балл составляет 71,33333333333333, средний балл - 71,4166666666666.
Я использую оператор JPQL:
SELECT NEW tld.jpqlsum.view.StringLine(
SUM(sf.finalScore)
, SUM(sa.finalScore)
, AVG(sf.finalScore)
, AVG(sa.finalScore)
, MIN(sf.finalScore)
, MIN(sa.finalScore)
, MAX(sf.finalScore)
, MAX(sa.finalScore)
)
FROM Game ga
JOIN ga.scores sf
JOIN ga.scores sa
WHERE ga.id <> 57 AND sf.roster.id = 1 AND sa.roster.id <> 1
GROUP BY sf.roster.id
Это должно дать кумулятивный обзор всех сыгранных игр команды (состав). Hibernate (HSQLDB и HSQLDialect) генерирует:
select
sum(scores1_.final_score) as col_0_0_,
sum(scores2_.final_score) as col_1_0_,
avg(cast(scores1_.final_score as double)) as col_2_0_,
avg(cast(scores2_.final_score as double)) as col_3_0_,
min(scores1_.final_score) as col_4_0_,
min(scores2_.final_score) as col_5_0_,
max(scores1_.final_score) as col_6_0_,
max(scores2_.final_score) as col_7_0_
from
Games game0_
inner join
Scores scores1_
on game0_.id=scores1_.game_id
inner join
Scores scores2_
on game0_.id=scores2_.game_id
where
game0_.id<>57
and scores1_.roster_id=1
and scores2_.roster_id<>1
group by
scores1_.roster_id
Как вы можете видеть, Hibernate правильно генерирует чередующиеся оценки1 и оценки2 в предложении select, но, очевидно, показывает кумулятивные значения только для оценок1:
|SUM(sf.finalScore)|SUM(sa.finalScore)|AVG(sf.finalScore)|AVG(sa.finalScore)|MIN(sf.finalScore)|MIN(sa.finalScore)|MAX(sf.finalScore)|MAX(sa.finalScore)|
|------------------|------------------|------------------|------------------|------------------|------------------|------------------|------------------|
| 856| 856| 71.33333333333333| 71.33333333333333| 50| 50| 89| 89|
Затем я попробовал MySQL и соответствующий MySQLDialect, который генерирует точно такой же код, за исключением того, что функции AVG удваиваются:
select
sum(scores1_.final_score) as col_0_0_,
sum(scores2_.final_score) as col_1_0_,
avg(scores1_.final_score) as col_2_0_,
avg(scores2_.final_score) as col_3_0_,
min(scores1_.final_score) as col_4_0_,
min(scores2_.final_score) as col_5_0_,
max(scores1_.final_score) as col_6_0_,
max(scores2_.final_score) as col_7_0_
from
Games game0_
inner join
Scores scores1_
on game0_.id=scores1_.game_id
inner join
Scores scores2_
on game0_.id=scores2_.game_id
where
game0_.id<>57
and scores1_.roster_id=1
and scores2_.roster_id<>1
group by
scores1_.roster_id
Hibernate на MySQL выдает правильный вывод:
|SUM(sf.finalScore)|SUM(sa.finalScore)|AVG(sf.finalScore)|AVG(sa.finalScore)|MIN(sf.finalScore)|MIN(sa.finalScore)|MAX(sf.finalScore)|MAX(sa.finalScore)|
|------------------|------------------|------------------|------------------|------------------|------------------|------------------|------------------|
| 856| 881| 71.3333| 73.4167| 50| 43| 89| 101|
Мне кажется, что это ошибка, но только в HSQLDB, что странно. В чем может быть проблема здесь? Какой компонент Hibernate может вызвать проблему? Я имею в виду, что код MySQL и HSQLDB различаются только для функции AVG, в которой на HSQLDB генерируется приведение (... как double), но разве это портит результирующий набор, как показано?
Вот SSCCE (JavaSE, Hibernate, HSQLDB, Ant):
http://www.kawoolutions.com/media/jpqlsum-hib-hsqldb-broken.zip
Просто наберите "ant run" из оболочки.
Если у вас также есть MySQL, xml / persistence.xml содержит закомментированный код для MySQL, чтобы вы могли легко переключаться между СУБД. Также загляните в каталог DB, который содержит дизайнерские PDF-файлы и сценарии DDL и INSERT в формате ISO / ANSI.
Обратите внимание, что я также тестировал HSQLDB с его диалектом и без него, а также MySQL с его диалектом и без него (задан в файле persistence.xml). И с и без показывают одинаковые результаты, HSQLDB показывает и неправильно, и MySQL показывает оба правильно.
Кто-нибудь может подтвердить эту ошибку? Тогда я отправлю отчет об ошибке ...
Карстен