Java 简单但复杂的HQL/SQL查询
我有两个表格,一对多的关系测验,评论:一个测验可以有多个评论 我需要在页面内显示每个测验的最后5条评论 如果没有,哪种方法是最好的,是否可以使用一个查询提取这些评论?现在,我正在为每个测验执行一个单独的查询,以提取最后5条注释 我希望能找到一个单一的HQL来允许我提取这些评论Java 简单但复杂的HQL/SQL查询,java,mysql,sql,jpa,hql,Java,Mysql,Sql,Jpa,Hql,我有两个表格,一对多的关系测验,评论:一个测验可以有多个评论 我需要在页面内显示每个测验的最后5条评论 如果没有,哪种方法是最好的,是否可以使用一个查询提取这些评论?现在,我正在为每个测验执行一个单独的查询,以提取最后5条注释 我希望能找到一个单一的HQL来允许我提取这些评论 另外,我正在使用hibernate/jpa/mysql,我认为您需要使用分析函数来实现这一点。这是一个例子 在cas中,sql查询如下所示: SELECT quizz_id, comment_id, comment_tex
另外,我正在使用hibernate/jpa/mysql,我认为您需要使用分析函数来实现这一点。这是一个例子 在cas中,sql查询如下所示:
SELECT quizz_id, comment_id, comment_text FROM (
SELECT c.quizz_id, c.comment_id, c.comment_text, ROW_NUMBER()
OVER (PARTITION BY c.quizz_id ORDER BY c.date DESC) AS rn
FROM comments c)
WHERE rn <= 5 order by quizz_id, rn;
但是您将无法使用HQL进行此类查询。我编写了一个复杂的SQL,它使用MySQL运行- 基本理念是: 对注释进行排序,并添加rownum作为排名。对同一个测验的评论已经产生了连续的数字排名 加入每个测验的最新评论的最大聚合 通过添加这些信息,可以构建where子句来限制每次测验的评论 前提条件是日期较新的注释具有较高的id 更新:已更改SQL。在我的一小部分测试数据中发现了一些缺失的测试用例 SQL的这一部分稍后将使用两次。。。您应该使用它创建一个视图
SELECT
@rownum:=@rownum+1 AS Rank,
c.*
FROM _comments c, (SELECT @rownum:=0) r
ORDER BY c.q_id, c.id
-
替代where子句:absmax_c.LastEntry_id-排名_c.Rank<5
->使用视图的解决方案:
我认为这在hql中是不可能的,但这是我使用标准sql的尝试:
SELECT
q.id AS quiz_id, c.id AS comment_id, c.text AS comment_text, c.date AS comment_date
FROM
quiz q
JOIN
comments c
ON
q.id = c.quiz_id
WHERE
c.id IN
(SELECT
id
FROM
comments c2
WHERE
c2.quiz_id = q.id
ORDER BY
date desc
LIMIT 5
)
ORDER BY
q.id ASC, c.date ASC
编辑:我认为这在hql中不可能的原因是,据我所知,它不支持限制,因为它不是标准SQL。这也意味着我的示例不是100%纯标准SQL,但mysql支持它——而且您使用mysql,所以我认为这没关系
EDIT2:修复了SQL,因为它是错误的。现在它使用了一个subselect,我不确定这是否很快,但我依赖那里的查询优化器^^。也在本地数据库postgres而不是mysql上测试了它,但它应该在这两种数据库中都能工作。对于频繁的编辑表示抱歉。我最初的测试数据没有涵盖现实生活中的用例,我发现我的代码每出现一个新的用例都会中断。这会返回5条最新的注释,但不是每个quizyeah返回5条最新的注释,我在本地测试中也注意到了这一点。现在我修好了,好主意。但是MySQL有一个令人讨厌的限制:测试了MySQL 5.1和5.5[错误代码:1235,SQL状态:42000]这个版本的MySQL还不支持“LIMIT&IN/ALL/ANY/SOME subquery”嗯,好吧,这使得我的示例不起作用。好的,那么你的帖子bw_uezi是唯一一个适用于mysql的。如果我已经可以投票了,我会投票支持你的答案。检查:检查:在这里检查其他标有GREATEST-n-per-group的问题
CREATE OR REPLACE VIEW V_RankedComments AS (
SELECT
@rownum:=@rownum+1 AS Rank,
c.*
FROM _comments c, (SELECT @rownum:=0) r
ORDER BY c.q_id, c.id
)
SELECT
ranked_c.*
FROM V_RankedComments ranked_c
INNER JOIN (
SELECT
i.q_id,
MAX(i.Rank) AS LastEntry_id
FROM V_RankedComments i
GROUP BY i.q_id
) max_c ON ranked_c.q_id = max_c.q_id
WHERE max_c.LastEntry_id - ranked_c.Rank BETWEEN 0 AND 4
SELECT
q.id AS quiz_id, c.id AS comment_id, c.text AS comment_text, c.date AS comment_date
FROM
quiz q
JOIN
comments c
ON
q.id = c.quiz_id
WHERE
c.id IN
(SELECT
id
FROM
comments c2
WHERE
c2.quiz_id = q.id
ORDER BY
date desc
LIMIT 5
)
ORDER BY
q.id ASC, c.date ASC