简单但复杂的HQL / SQL查询

时间:2011-02-23 09:02:35

标签: java mysql sql jpa hql

我有两个表,一对多的关系(测验,评论):一个测验可以有多个评论

我需要在页面内显示每个测验的最后5条评论。

是否可以使用一个查询提取这些评论(如果不是,这是最好的方法)?现在我正在为每个测验执行单独的查询以提取最后5条评论。

(我希望找到一个单独的HQL来允许我提取这些评论)

PS。我正在使用hibernate / jpa / mysql

3 个答案:

答案 0 :(得分:2)

我写了一个用MySQL运行的复杂SQL ;-)
基本理念是:

  • 订购评论并添加rownum作为排名。对同一个quizz的评论产生了连续数字的排名
  • 使用每个quizz的最新评论加入最大聚合
  • 使用此添加的信息,可以构建一个where子句来限制每个quizz的注释

前置条件是较新date的评论有较高的id

更新:更改了SQL。 (在我的一小组测试数据中实现了一些缺少的测试用例)
这部分SQL后来使用了两次......你应该用它创建一个View。

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 (
    SELECT 
      @rownum:=@rownum+1 AS Rank,
      c.*
    FROM _comments c, (SELECT @rownum:=0) r
    ORDER BY  c.q_id, c.id
  ) ranked_c
  INNER JOIN (
    SELECT 
      i.q_id,
      MAX(i.Rank) AS LastEntry_id
    FROM  (
      SELECT 
        @rownum:=@rownum+1 AS Rank,
        c.*
      FROM _comments c, (SELECT @rownum:=0) r
      ORDER BY c.q_id, c.id
    ) 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 

替代where子句:abs(max_c.LastEntry_id - ranked_c.Rank) < 5

<强> - &GT;使用视图的解决方案:

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 

答案 1 :(得分:0)

我认为你需要使用分析函数来做到这一点。这是一个example for Oracle

在你的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进行这种查询。

答案 2 :(得分:0)

我不认为这在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中是不可能的原因是因为据我所知它不支持LIMIT,因为它不是标准的SQL。这也意味着我的示例不是100%纯标准SQL,但是mysql支持它 - 而且你使用mysql,所以我认为没关系。

EDIT2:修正了SQL,因为它错了。现在它使用了一个subselect(我不确定这是否很快,但我依赖于那里的查询优化器^^)。还在本地数据库上测试了它(postgres而不是mysql,但它应该在两者中都有效)。