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;
Produce il risultato desiderato.
-
Riscrivi con
JOIN
esplicito sintassi. Semplifica molto la lettura e la comprensione (e il debug). -
Unendo a più
1:n
tabelle correlate, le righe si moltiplicherebbero a vicenda producendo un prodotto cartesiano - che è una sciocchezza molto costosa. È unCROSS JOIN
non intenzionale per delega. Correlati: -
Per evitare ciò, unisciti al massimo a uno
n
-tabella al1
-table prima di aggregare (GROUP BY
). Puoi aggregare due volte, ma è più semplice e veloce aggregaren
-tabelle separatamente prima unendoli al1
-tavolo. -
Al contrario del tuo originale (con
INNER JOIN
implicito ). UsoLEFT JOIN
per evitare di perdere righe dafoo
che non hanno una riga corrispondente infoo_bar
otag
. -
Dopo l'indesiderato
CROSS JOIN
viene rimosso dalla query, non è necessario aggiungereDISTINCT
più - supponendo chefoo.id
è unico.