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つのクエリの唯一の違いは、結合する前に行を制限するために後者でサブクエリを使用していることです。このエラーを解決するにはどうすればよいですか?
GROUP BY
でテーブルの主キーを使用でき、GROUP BY
句にそのテーブルの他の列を追加する必要がないPostgresの機能は比較的新しいもので、ベーステーブルでのみ機能します。オプティマイザーは(まだ?)(あなたの場合のように)ビュー、Ctes、または派生テーブルの主キーを識別するのに十分ではありません。
SELECT
の必要な列をGROUP 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 ;