2014-12-22 3 views
1

У меня есть следующие items таблица:Объединяя три таблицы с агрегацией

items: 
id pr1 pr2 pr3 
------------------- 
1  11 22 tt 
... 

и две таблицы, связанные с деталями:

comments: 
item_id text 
------------- 
1  "cool" 
1  "very good" 
... 

tags: 
item_id tag 
------------- 
1  "life" 
1  "drug" 
... 

Теперь я хочу, чтобы получить таблицу со столбцами item_id, pr1, pr2, count(comments), count(tags) с условием WHERE pr3 = zz. Каков наилучший способ получить его? Я могу сделать это, создав дополнительные таблицы, но мне было интересно, есть ли способ достичь этого, используя только один оператор SQL. Я использую Postgres 9.3.

+0

Да, вы ищете внутреннее соединение между ese три таблицы. – SMA

+0

@Saharsh Shah: Я снова удалил тэги. Это не вопрос о левых объединениях и т. Д., А о том, как написать ** SQL **-запрос в ** PostgreSQL **, как правильно отмечено. Да, внешнее соединение таблиц - это одно решение, но не единственное. –

+0

Наиболее эффективный запрос зависит от того, хотите ли вы получить все или большинство элементов одновременно или только небольшой выбор или отдельный элемент. Вы должны уточнить свой вопрос в этом отношении. Добавьте свою версию Postgres, находясь на ней. –

ответ

2

Самый простой способ, конечно, чтобы получить отсчеты в выбранном пункте:

select 
    id, 
    pr1, 
    pr2, 
    (select count(*) from comments where item_id = items.id) as comment_count, 
    (select count(*) from tags where item_id = items.id) as tag_count 
from items; 
+0

Зачем вам это делать? Это SELECT для каждой строки (фактически два), вместо того, чтобы дать оптимизатору наилучшую возможную возможность консолидировать вещи. – davek

+0

Отсутствует запятая после «comment_count» ... – mlinth

+0

@mlinth: Thank's. Я отредактирую. –

-1
select 

    i.id 
, i.pr1 
, i.pr2 
, count(c.item_id) as count_comments 
, count(t.item_id) as count_tags 

from items i 
left outer join comments c on i.id = c.item_id 
left outer join tags t on i.id = t.item_id 
group by i.id, i.pr1, i.pr2 

Я использовал LEFT OUTER JOIN, чтобы также возвращать отсчеты от нуля.

+0

Этот запрос не будет выполняться, потому что pr1 и pr2 не находятся в группе по выражению, а также возвращают неправильные результаты, потому что count (distinct (item_id) будет 1 ... Просто попробовал ... – mlinth

+0

@mlinth: well пятнистый! Редактировали соответственно. – davek

+0

@ davek ваш запрос возвращает либо 'count_comments', и' count_tags' равные друг другу, и ненулевые, или один из них 0. – hovo

2

Вы можете просто присоединиться, но вам нужно быть осторожным, чтобы вы не получили двойной счет. Например. вы можете использовать подзапросы, чтобы получить то, что хотите.

SELECT i.id,i.pr1,i.pr2, commentcount,tagcount FROM 
items i 
INNER JOIN 
    (SELECT item_id,count(*) as commentcount from comments GROUP BY item_id) c 
ON i.id = c.item_id 
INNER JOIN 
    (SELECT item_id,count(*) as tagcount from tags GROUP BY item_id) t 
ON i.id = t.item_id 

[EDIT] на основе комментария, вот слева присоединиться к версии ...

SELECT i.id,i.pr1,i.pr2, coalesce(commentcount,0) as commentcount, 
     coalesce(tagcount,0) as tagcount FROM 
    items i 
    LEFT JOIN 
     (SELECT item_id,count(*) as commentcount from comments GROUP BY item_id) c 
    ON i.id = c.item_id 
    LEFT JOIN 
     (SELECT item_id,count(*) as tagcount from tags GROUP BY item_id) t 
    ON i.id = t.item_id 
+1

Это хороший ответ. Сделайте эти внешние соединения и получите доступ к счетчикам с помощью 'coalesce (commentcount, 0)' и 'coalesce (tagcount, 0)', так что вы также получите элементы с нулевыми комментариями или тегами. –

+0

Я пробовал этот запрос. Он работает, но на Postgres 9 он очень медленный.3. Я думаю, что причина проблемы заключается в том, что я не упоминал в вопросе: в конце запроса есть предложение WHERE i.pr3 = smth'. В случае вашего запроса заключенные в скобки варианты в этом запросе оцениваются на всех 'i.item_id' вместо всего небольшого набора из них. Таким образом, запрос, в котором вы просто «LEFT JOIN» на всех трех таблицах, затем вычисляет количество чисел, выполняется намного быстрее. Я не знаю, почему Postgres не может это оптимизировать. – hovo

1

Попробуйте следующее:

SELECT i.id, i.pr1, i.pr2, A.commentCount, B.tagCount 
FROM items i 
LEFT OUTER JOIN (SELECT item_id, COUNT(1) AS commentCount 
       FROM comments 
       GROUP BY item_id 
       ) AS A ON i.id = A.item_id 
LEFT OUTER JOIN (SELECT item_id, count(1) as tagCount 
       FROM tags 
       GROUP BY item_id 
       ) AS B ON i.id = B.item_id; 
Смежные вопросы