Hibernate JPQL / HQL: ошибка с агрегатными функциями, показывающая результаты неверной таблицы / сущности, объединенной дважды (только с использованием HSQLDB)? - PullRequest
1 голос
/ 07 декабря 2010

У меня есть следующие таблицы:

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 показывает оба правильно.

Кто-нибудь может подтвердить эту ошибку? Тогда я отправлю отчет об ошибке ...

Карстен

1 Ответ

2 голосов
/ 07 декабря 2010

В HSQLDB произошла ошибка, которая приводила к одинаковому совокупному результату для одного и того же столбца из двух версий одной и той же таблицы. Это было исправлено в последних версиях 2.0.1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...