SELECT f.id, f.name, b.fb_ct, t.tag_names
FROM foo f
LEFT JOIN (
SELECT foo_id AS id, count(*) AS fb_ct
FROM foo_bar
GROUP BY 1
) b USING (id)
LEFT JOIN (
SELECT target_id AS id, array_agg(name) AS tag_names
FROM tag
GROUP BY 1
) t USING (id)
ORDER BY f.id;
Дава желания резултат.
-
Пренапишете с изричен
JOIN
синтаксис. Прави го много по-лесно за четене и разбиране (и отстраняване на грешки). -
Чрез присъединяване към множество
1:n
свързани таблици, редовете ще се умножават взаимно, създавайки декартово произведение - което е много скъпа глупост. Това е нежеланоCROSS JOIN
чрез пълномощник. Свързани: -
За да избегнете това, присъединете се към най-много един
n
-таблица към1
-таблица, преди да обобщите (GROUP BY
). Можете да обобщите два пъти, но е по-чисто и по-бързо да обобщитеn
-таблици отделно преди присъединявайки ги към1
- маса. -
За разлика от вашия оригинал (с имплицитно
INNER JOIN
). ИзползвамLEFT JOIN
за да избегнете загуба на редове отfoo
които нямат съответстващ ред вfoo_bar
илиtag
. -
След нежеланото
CROSS JOIN
е премахнат от заявката, няма нужда от добавяне наDISTINCT
повече - ако приемем, чеfoo.id
е уникален.