2009-07-16 24 views
8

は、私はこのようなクエリがある:なぜPostgresの "SELECT foo。* ... GROUP BY foo.id"はありませんか?

select foo.*, count(bar.id) 
from foo inner join bar on foo.id = bar.foo_id 
group by foo.id 

これは、SQLiteのとMySQLで素晴らしい仕事しました。しかし、Postgresはgroup by節にfooのすべての列を含めないと私に不平を言う。どうしてこれなの? foo.idがユニークなのは十分ではありませんか?

+0

ステートメントにgroup by句はありません...あなたはそれを忘れましたか? –

+5

mysqlがそれを受け入れるからといってそれが良いアイデアや正しい方法であるとは限りません。 – nos

答えて

26

他の人がこの質問の上につまずく念のために:

は、PostgreSQL 9.1以降では、それは主キーの列を一覧表示するには十分ですgroup by節(この質問の例が今ではうまくいくでしょう)。

+0

優秀、この小さな宝石をありがとう! – kwarrick

+0

私はmysqlから移行した後の夕方、pgのこの奇妙な動作に対処できませんでした:) Thanx – kovpack

+3

@kovpack:これはPostgresの「奇妙な動作」ではありません。 Postgresは、SQL標準や他のすべてのDBMSで必要に応じて動作します。ここでは奇妙なMySQLです(壊れているとは言えません) –

3

正確にpostgresqlの出力はありますか?集計関数を使用していて、「何か」を出力しようとしています。

ああ。私はあなたがしたいことがあるかを見ます。副選択を使用します。

select foo.*, (select count(*) from bar where bar.foo_id=foo.id) from foo; 

プランがうまくいくように確認します。副選択が必ずしも悪いとは限りません。私は使用しているデータベースにチェックしたところ、実行計画はそのクエリに適していました。

はい、理論的には、foo.idによるグループ分けで十分です(クエリに「foo.id」でグループ化されたもの)。しかし、明らかに(私はそれをテストした)postgresqlはそれをしません。もう1つのオプションは、 "foo.id、foo.foo、foo.bar、foo.baz"と "foo。*"にあるその他のものでグループ化することです。

別の方法として、Guffaがに上であること、これは次のようになります。

SELECT foo.*, COALESCE(sub.cnt, 0) 
FROM foo 
LEFT OUTER JOIN (
    SELECT foo_id, count(*) AS cnt 
    FROM bar 
    GROUP BY foo_id) sub 
ON sub.foo_id = foo.id; 

これは問題では、おそらくないでしょうができます(一度だけ実行される1つのサブクエリ、)しかし2つのクエリになります。 "foo。*"を使わずに行えるのであれば、明示的にすべての列でグループ化する2番目のバージョンを使うことができます。

1

GROUP BY句では、クエリが返すすべての列が、GROUP BYステートメントに含まれる列か、集計関数(例ではなど)である必要があります。あなたのGROUP BY句が何であるか、またはfooの列が何であるかを見ることなく、正確に何が起こっているのかを知るのは難しいですが、foo.*GROUP BY句にない1つ以上の列を返そうとしていると思います。

これは実際にはSQLの一般的なプロパティであり、PostgreSQL固有のものではありません。なぜそれがSQLiteやMySQLでうまくいったのか分かりません。foo.*のすべてのカラムは実際にはGROUP BY節にありますが、PostgreSQLはそれを理解できません。したがって、fooのすべてのカラムを明示的にリストアップしてみてください。

3

データベースの中には、これについてもっと良いものと悪いものがあります。クエリーは非特異的であるため、結果も同様に非特異的です。データベースがクエリを許可する場合は、各グループから1つのレコードが返され、どちらのレコードも気にしません。他のデータベースはより具体的で、グループからどの値を指定する必要があります。彼らは、あなたが非特定の結果を持つクエリを書くことはできません。

あなたは集計せずに選択することができる唯一の値はgroup by句でのものです:あなたはすべての場合

select foo.id, count(bar.id) 
from foo inner join bar on foo.id = bar.foo_id 
group by foo.id 

あなたは他の値を取得するために凝集体を使用することができます値をfooテーブルから取得する場合は、group by句にすべての値を入れることができます(正しい結果が得られた場合)。

select foo.id, foo.price, foo.name, foo.address, count(bar.id) 
from foo inner join bar on foo.id = bar.foo_id 
group by foo.id, foo.price, foo.name, foo.address 

それとも、あなたはサブクエリでテーブルを結合することができます。

select foo.id, foo.price, foo.name, foo.address, sub.bar_count 
from foo 
inner join (
    select foo.id, bar_count = count(bar.id) 
    from foo inner join bar on foo.id = bar.foo_id 
    group by foo.id 
) sub on sub.id = foo.id 
+0

"a foo"のバーには何も入力しなければ、最後のものは動作しません:SELECT foo。* 、COALESCE(sub.bar_count)from foo左外部join(select ...)sub sub.id = foo.id; – Thomas

+0

また、副選択で結合を行う必要はありません。 – Thomas

+0

err ..私のコメントのバージョンはいくつかの文字を欠場しました。私が言ったことについて私の答えを見てください。 – Thomas

関連する問題