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;
Ger önskat resultat.
-
Skriv om med explicit
JOIN
syntax. Gör det så mycket lättare att läsa och förstå (och felsöka). -
Genom att gå med i flera
1:n
relaterade tabeller, skulle rader multiplicera varandra och producera en kartesisk produkt – vilket är väldigt dyrt nonsens. Det är en oavsiktligCROSS JOIN
genom ombud. Relaterat: -
För att undvika detta, gå med som mest ett
n
-tabell till1
-tabell innan du aggregerar (GROUP BY
). Du kan aggregera två gånger, men det är renare och snabbare att aggregeran
-tabeller separat före koppla dem till1
-tabell. -
I motsats till ditt original (med implicit
INNER JOIN
). Jag använderLEFT JOIN
för att undvika att tappa rader frånfoo
som inte har någon matchande rad ifoo_bar
ellertag
. -
När den oavsiktliga
CROSS JOIN
tas bort från frågan, finns det inget behov av att lägga tillDISTINCT
längre - förutsatt attfoo.id
är unik.