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;
Produit le résultat souhaité.
-
Réécrire avec un
JOIN
explicite syntaxe. Facilite grandement la lecture et la compréhension (et le débogage). -
En se joignant à plusieurs
1:n
tables liées, les lignes se multiplieraient produisant un produit cartésien - ce qui est un non-sens très coûteux. C'est unCROSS JOIN
involontaire par procuration. Connexe : -
Pour éviter cela, rejoignez au plus un
n
-table au1
-table avant d'agréger (GROUP BY
). Vous pouvez agréger deux fois, mais c'est plus propre et plus rapide d'agrégern
-tables séparément avant les joindre au1
-table. -
Contrairement à votre original (avec
INNER JOIN
implicite ). J'utiliseLEFT JOIN
pour éviter de perdre des lignes defoo
qui n'ont pas de ligne correspondante dansfoo_bar
outag
. -
Une fois le
CROSS JOIN
involontaire est supprimé de la requête, il n'est pas nécessaire d'ajouterDISTINCT
plus - en supposant quefoo.id
est unique.