サブクエリを使用する場合のPostgresエラー[GROUP BY句に表示するか、集計関数で使用する必要があります]


16

2つのテーブルemployeeとがありphonesます。従業員は0〜n個の電話番号を持つことができます。従業員の名前と電話番号をリストしたいと思います。私はうまく動作する以下のクエリを使用しています。

SELECT empname,array_agg(phonenumber) AS phonenumbers 
FROM employee LEFT OUTER JOIN phones ON employee.empid = phones.empid
GROUP BY employee.empid

ここに画像の説明を入力してください

従業員表には多数の行が含まれる場合があります。一度に数人の従業員のみを取得します。たとえば、電話番号で3人の従業員を取得します。このクエリを実行しようとしています。

SELECT empname,array_agg(phonenumber) AS phonenumbers 
FROM 
(SELECT * FROM employee ORDER BY empname LIMIT 3 OFFSET 0) AS employee 
LEFT OUTER JOIN phones ON employee.empid = phones.empid
GROUP BY employee.empid

しかし、私はこのエラーを受け取ります。ERROR: column "employee.empname" must appear in the GROUP BY clause or be used in an aggregate function 2つのクエリの唯一の違いは、後者のサブクエリを使用して、結合する前に行を制限することです。このエラーを解決するにはどうすればよいですか?

回答:


21

テーブルの主キーを使用してGROUP BY、そのテーブルの他の列をGROUP BY句に追加する必要がないPostgresの機能は比較的新しく、ベーステーブルでのみ機能します。オプティマイザは(まだ?)ビュー、ctes、または派生テーブル(主な場合)の主キーを識別するのに十分ではありません。

あなたは、あなたがしたい列を追加することができますSELECTGROUP BY句:

SELECT e.empname, array_agg(p.phonenumber) AS phonenumbers 
FROM 
(SELECT * FROM employee ORDER BY empname LIMIT 3 OFFSET 0) AS e 
LEFT OUTER JOIN phones AS p ON e.empid = p.empid
GROUP BY e.empid, e.empname 
ORDER BY e.empname ;

または、サブクエリを使用します(そしてGROUP BYそこに転送します):

SELECT e.empname,
       (SELECT array_agg(p.phonenumber) 
        FROM phones AS p
        WHERE e.empid = p.empid
       ) AS phonenumbers 
FROM 
(SELECT * FROM employee ORDER BY empname LIMIT 3 OFFSET 0) AS e 
ORDER BY e.empname ;

次のように書くこともできます。

SELECT e.empname,
       (SELECT array_agg(p.phonenumber) 
        FROM phones AS p
        WHERE e.empid = p.empid
       ) AS phonenumbers 
FROM employee AS e
ORDER BY e.empname LIMIT 3 OFFSET 0 ;

バージョン9.3以降であるため。LATERAL結合を使用することもできます:

SELECT e.empname,
       p.phonenumbers 
FROM 
   (SELECT * FROM employee ORDER BY empname LIMIT 3 OFFSET 0) AS e
LEFT JOIN LATERAL
   (SELECT array_agg(phonenumber) AS phonenumbers
    FROM phones 
    WHERE e.empid = phones.empid
   ) AS p ON TRUE 
ORDER BY e.empname ;

@ypercudeありがとう。これはシンプルでクリーンな方法です。
プログラマー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.