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;
Produceert het gewenste resultaat.
-
Herschrijven met expliciete
JOIN
syntaxis. Maakt het zoveel gemakkelijker te lezen en te begrijpen (en debuggen). -
Door lid te worden van meerdere
1:n
gerelateerde tabellen, zouden rijen elkaar vermenigvuldigen en een Cartesiaans product produceren - wat erg dure onzin is. Het is een onbedoeldeCROSS JOIN
bij volmacht. Gerelateerd: -
Om dit te voorkomen, moet u maximaal één deelnemen
n
-tabel naar de1
-tabel voordat u aggregeert (GROUP BY
). Je zou twee keer kunnen aggregeren, maar het is schoner en sneller omn
te aggregeren -tabellen afzonderlijk voor voeg ze toe aan de1
-tafel. -
In tegenstelling tot uw originele (met impliciete
INNER JOIN
). Ik gebruikLEFT JOIN
om te voorkomen dat u rijen verliest vanfoo
die geen overeenkomende rij hebben infoo_bar
oftag
. -
Zodra de onbedoelde
CROSS JOIN
is verwijderd uit de zoekopdracht, is het niet nodig omDISTINCT
toe te voegen meer - ervan uitgaande datfoo.id
is uniek.