Hibernate JPQL/HQL:聚合函数的错误显示错误的表/实体连接两次(仅使用 HSQLDB)的结果?
Posted
技术标签:
【中文标题】Hibernate JPQL/HQL:聚合函数的错误显示错误的表/实体连接两次(仅使用 HSQLDB)的结果?【英文标题】:Hibernate JPQL/HQL: bug with aggregate functions showing results of wrong table/entity joined twice (using HSQLDB only)? 【发布时间】:2010-12-07 12:46:15 【问题描述】:我有以下表格:
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)
);
简单的逻辑,一场比赛有两个比分,主场和客场(在PK中通过is_home),它们与一个花名册ID相关联。分数表基本上是游戏和花名册之间的连接表。我相应地映射了类(这里没有问题):
这是我接下来要汇总的数据(14 场比赛,28 场得分,[sf] 的 14 场得分,[sa] 的 14 场得分,以及 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 在 select 子句中正确生成了交替的 scores1 和 scores2,但显然只显示了 score1 的累积值:
|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 函数强制转换为 double:
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 on 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 代码仅对在 HSQLDB 上生成 cast(... as double) 的 AVG 函数有所不同,但这是否会混淆结果集,如图所示?
这是一个 SSCCE(JavaSE、Hibernate、HSQLDB、Ant): http://www.kawoolutions.com/media/jpqlsum-hib-hsqldb-broken.zip
只需在 shell 中输入“ant run”即可。
如果您还有 MySQL,则 xml/persistence.xml 包含 MySQL 的注释代码,因此您可以轻松切换 DBMS。还要查看 DB 目录,其中包含设计 PDF 和 ISO/ANSI DDL 和 INSERT 脚本。
注意,我还测试了有和没有方言的 HSQLDB 以及有和没有方言的 MySQL(在 persistence.xml 中设置)。无论有无都显示相同的结果,HSQLDB 都显示错误,MySQL 都显示正确。
谁能确认这个错误?然后我会提交一个错误报告...
卡斯滕
【问题讨论】:
【参考方案1】:HSQLDB 中存在一个错误,它从同一个表的两个版本中为同一列生成相同的聚合结果。这已在最新的 2.0.1 jar 中修复。
【讨论】:
以上是关于Hibernate JPQL/HQL:聚合函数的错误显示错误的表/实体连接两次(仅使用 HSQLDB)的结果?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 IntelliJ 12 中启用 HQL/JPQL 自动完成
Atitit oodbms的查询,面向对象的sql查询jpa jpql hql