2つのテーブルがあるとします。
フー:
id
baz
バー:
id
foo_id
boom
したがって、Fooには多くのバーがあります。特定のFoosのセットについてバー全体の集計を計算する必要がある状況に頻繁に気付きますが、Fooのいくつかのプロパティも必要です。これを行う最も簡単な2つの方法は醜いです。
方法1:不要な集計関数
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;
方法2:列による不要なグループ化
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;
「id」以外にFooからの列が1つしかない場合、これはそれほど問題ではありませんが、含める必要のある列が多い場合、グループ化の効率は大幅に低下します。このようなクエリは、これらの両方の問題を回避しますが、扱いにくいようです。
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;
もっと良い方法はありますか?それが重要な場合、プラットフォームはPostgresです。
idが主キーとして定義されている場合、出力に必要なすべてのfoo列によるグループ化を省略できます。 idでグループ化しています。このグループ化の特殊なケースは、現在のSQL標準に準拠しており、バージョン9.1以降の PostgreSQLマニュアル でも説明されています。
GROUP BYが存在する場合、または集約関数が存在する場合、集約関数内内を除いて、またはグループ化されていない列がグループ化された列。グループ化されていない列に対して返される可能性のある値が複数あるためです。 グループ化された列(またはそのサブセット)がグループ化されていない列を含むテーブルの主キーである場合、機能的な依存関係が存在します。
(強調が追加されました。)
したがって、foo.idがPKである場合、このクエリは有効です。
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;
PostgreSQLのDISTINCT ONは非常に洗練されており、非常によく機能します(多くの場合、集約よりも優れています)。
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;
または
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;