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;
Vytváří požadovaný výsledek.
-
Přepište pomocí explicitního
JOIN
syntax. Je to mnohem snazší číst a pochopit (a ladit). -
Připojením k více
1:n
související tabulky, řádky by se navzájem násobily a vytvořily by kartézský produkt - což je velmi drahý nesmysl. Je to nechtěnéCROSS JOIN
přes proxy. Související: -
Chcete-li se tomu vyhnout, připojte se nejvýše k jednému
n
-tabulka na1
-table před agregací (GROUP BY
). Můžete agregovat dvakrát, ale je čistší a rychlejší agregovatn
-tabulky samostatně před jejich připojením k1
-stůl. -
Na rozdíl od vašeho originálu (s implicitním
INNER JOIN
). PoužívámLEFT JOIN
aby nedošlo ke ztrátě řádků zfoo
které nemají žádný odpovídající řádek vfoo_bar
nebotag
. -
Jakmile dojde k nechtěnému
CROSS JOIN
je z dotazu odstraněn, není třeba přidávatDISTINCT
nic víc - za předpokladu, žefoo.id
je jedinečný.