Как сделать запрос SELECT в Hibernate включает в себя подзапрос COUNT (*) - PullRequest
3 голосов
/ 24 марта 2012

Допустим, у нас есть Категория - Предметы отношение один-ко-многим . Я хотел бы сделать это

SELECT c.*, 
   (SELECT COUNT(*) FROM items i WHERE i.catId=c.id)
    AS itemCount
FROM category c

И скажем, у нас есть Hibernate POJO "категория класса".

Мой первый вопрос: я действительно не могу понять, что из этого запроса я получаю объект List , верно? И как я могу получить доступ к "itemCount"? Потому что нет Category.getItemCount ()

А во-вторых, как мне написать запрос Criteria?

Спасибо

Ответы [ 3 ]

6 голосов
/ 25 марта 2012

Похоже, это ответ, который я искал (в POJO):

@Formula(value="(SELECT COUNT(*) FROM Items i WHERE i.id = id)")
@Basic(fetch=FetchType.EAGER)
public Integer getItemCount() {
   return this.taskCount;
}
2 голосов
/ 24 марта 2012

В зависимости от ваших обстоятельств и способности создавать вид.Я бы просто создал представление из вашего запроса:

CREATE VIEW CategoryItemsView AS 
    SELECT c.*,  
   (SELECT COUNT(*) FROM items i WHERE i.catId=c.id) 
    AS itemCount 
FROM category c 

, после чего вы можете запросить, как вам нравится ...

SELECT * FROM CategoryItemsView WHERE ItemCount = 5

Кроме того, вы можете использовать GROUP BY для достиженияпохожий результат, но это зависит от ваших столбцов и схемы ваших таблиц.

Итак, что-то вроде этого:

SELECT c.COLUMN1, c.COLUMN2, COUNT(*) AS ItemCount
FROM category c inner join items i on i.catID = c.Id
GROUP BY c.COLUMN1, c.COLUMN2
HAVING COUNT(*) = 2
1 голос
/ 24 марта 2012

О запросе

Вдохновленный комментарием @ a_horse Я провел быстрый тест с реальной таблицей для аналогичной цели.

  • 80 категорий
  • 6862items
  • оптимальные индексы (на items.catID. Здесь больше, но не полезно.)

Три кандидата.Результаты идентичны.Планы и производительность запросов различаются.

1) Подвыбрать для каждой категории (оригинал Серегветрина)

Общее время выполнения: 20,351 мс

SELECT c.*
      ,(SELECT COUNT(*) FROM items i WHERE i.catid = c.id) AS item_ct
FROM category c

2) ВЛЕВО, затем ГРУППА

Общее время выполнения: 36,320 мс

SELECT c.*
      ,count(*) AS item_ct
FROM   category c
LEFT   JOIN items i ON i.catid = c.id
GROUP  BY c.catid;  -- prim. key of category

3) GROUP, затем LEFT JOIN

Общее время выполнения: 18,588 мс

SELECT c.*
      ,item_ct
FROM   category c
LEFT   JOIN  (
    SELECT catid
          ,count(*) AS item_ct
    FROM   items
    GROUP  BY catid
    ) i ON i.catid = c.id

Итак, мое первое предложение не принесло пользы.Как и ожидалось (после некоторых раздумий), версия 3) работает лучше всего.Это также имеет смысл: если сначала посчитать, а затем СОЕДИНИТЬ, то потребуется меньше операций объединения.

Разница в производительности станет более заметной для больших таблиц, особенно с большим количеством категорий.

Чтобы 2) работало, вам нужен PostgreSQL 9.1, а category.id должен быть первичным ключом.
Для более старых версий вам придется перечислять все неагрегированные столбцы в предложении GROUP BY.

Как правило, я переключился на LEFT JOIN, поскольку исходный запрос включает категории без связанных элементов.

Индекс items.catID используется только в 1), когда несколько подзапросов могут получить прибыль.В других запросах последовательное сканирование выполняется быстрее: все обе таблицы должны быть прочитаны в любом случае.

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