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
JOINexplicite syntaxe. Facilite grandement la lecture et la compréhension (et le débogage). -
En se joignant à plusieurs
1:ntables liées, les lignes se multiplieraient produisant un produit cartésien - ce qui est un non-sens très coûteux. C'est unCROSS JOINinvolontaire 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 JOINimplicite ). J'utiliseLEFT JOINpour éviter de perdre des lignes defooqui n'ont pas de ligne correspondante dansfoo_baroutag. -
Une fois le
CROSS JOINinvolontaire est supprimé de la requête, il n'est pas nécessaire d'ajouterDISTINCTplus - en supposant quefoo.idest unique.