Простой, но сложный HQL / SQL-запрос - PullRequest
3 голосов
/ 23 февраля 2011

У меня есть две таблицы, в отношении «один ко многим» (тесты, комментарии): у теста может быть несколько комментариев

Мне нужно отобразить на странице последние 5 комментариев для каждого теста.

Можно ли извлечь тезисные комментарии с помощью одного запроса (если нет, то какой способ лучше всего сделать)? Сейчас я выполняю отдельный запрос для каждого теста, чтобы извлечь последние 5 комментариев.

(я надеюсь найти один HQL, который позволил бы мне получать комментарии к тезисам)

пс. Я использую hibernate / jpa / mysql

Ответы [ 3 ]

2 голосов
/ 23 февраля 2011

Я написал сложный SQL, который работает с MySQL ;-)основная идея:

  • Заказать комментарии и добавить rownum в качестве ранга.комментарии к одному и тому же опросу сгенерировали ранги с непрерывными числами
  • объединить максимальное агрегирование с последним комментарием для каждого запроса
  • с помощью этой дополнительной информации можно создать предложение where для ограничения количества комментариев к опросу

Предварительное условие состоит в том, что комментарий с более новым 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 

альтернатива, где пункт: abs(max_c.LastEntry_id - ranked_c.Rank) < 5

-> Решение с использованием представления:

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 
0 голосов
/ 23 февраля 2011

Я не думаю, что это возможно в 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, потому что он был неправильным. Теперь он использует подвыбор (я не уверен, что это быстро, но я полагаюсь на оптимизатор запросов там ^^). Также проверил его в локальной базе данных (postgres вместо mysql, но он должен работать в обеих).

0 голосов
/ 23 февраля 2011

Я думаю, вам нужно использовать аналитические функции для этого. Вот пример для 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 для такого рода запросов.

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