Supposons que j'ai deux tables:
foo :
id
baz
barre :
id
foo_id
boom
Donc, un foo a beaucoup de barres. Je me trouve souvent dans des situations où j'ai besoin de calculer un agrégat dans les barres pour un ensemble donné de Foos, mais je veux aussi des propriétés de FOO. Les deux façons les plus simples de faire cela sont laids:
Méthode n ° 1: fonctions d'agrégat inutiles
select
foo.id,
min(foo.baz) as baz,
min(bar.boom) as min_boom
from
foo
join
bar on foo.id = bar.foo_id
group by
foo.id;
Méthode n ° 2: groupe inutile par colonne
select
foo.id,
foo.baz,
min(bar.boom) as min_boom
from
foo
join
bar on foo.id = bar.foo_id
group by
foo.id,
foo.baz;
Ce n'est pas si mauvais quand il n'y a qu'une seule colonne supplémentaire de FOO à part "ID", mais s'il y a beaucoup de colonnes à inclure, le groupement devient beaucoup moins efficace. Une requête comme celle-ci se déplace à la fois ces problèmes, mais semble lourd:
select
foo.id,
foo.baz,
x.min_boom
from
foo
join
(select
foo_id,
min(boom) as min_boom
from
bar
group by
foo_id) x on x.foo_id = foo.id;
Y a-t-il une meilleure façon? La plate-forme est postgres si cela importe.
Si ID est défini comme clé primaire, vous pouvez omettre le regroupement par tous les colonnes FOO Colonnes que vous souhaitez pour la sortie tant que vous regroupez par le = ID. Ce cas particulier de regroupement est conforme à la norme SQL actuelle et a également été traitée dans le Manuel PostgreSQL , à partir de la version 9.1:
Lorsque le groupe par est présent ou toutes les fonctions globales sont présentes, il n'est pas valide pour les expressions de liste de sélection de sélectionner des colonnes non groupées, à l'exception des fonctions globales ou lorsque la colonne non groupée dépend de la fonction de regroupement , comme il serait autrement plus d'une valeur possible pour revenir à une colonne non groupée. ne dépendance fonctionnelle existe si les colonnes regroupées (ou un sous-ensemble) sont la clé primaire du tableau contenant la colonne non groupée.
((emphase).)
Donc, si FOO.ID est le PK, cette requête serait valide:
select
foo.id,
foo.baz,
foo.whatever,
min(bar.boom) as min_boom
from
foo
join
bar on foo.id = bar.foo_id
group by
foo.id;
Le distinct de postgreSQL est très élégant et se produit très bien (souvent mieux que les agrégats):
select DISTINCT ON (foo.id, foo.baz)
foo.id,
foo.baz,
bar.boom as min_boom
from
foo
join
bar on foo.id = bar.foo_id
ORDER BY
foo.id,
foo.baz,
bar.boom;
Ou alors
select
foo.id,
foo.baz,
x.min_boom
from
foo
join
(select DISTINCT ON (foo_id)
foo_id,
boom as min_boom
from
bar
ORDER BY
foo_id,
boom) x on x.foo_id = foo.id;