Pro*_*mer 25 postgresql aggregate subquery group-by
我有两张桌子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
Run Code Online (Sandbox Code Playgroud)

员工表可能包含大量行。我想一次只取一些员工。例如,我想用他们的电话号码获取 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
Run Code Online (Sandbox Code Playgroud)
但我收到这个错误。ERROR: column "employee.empname" must appear in the GROUP BY clause or be used in an aggregate function
两个查询之间的唯一区别是我在后者中使用子查询来限制加入之前的行。我该如何解决这个错误?
ype*_*eᵀᴹ 27
Postgres 能够使用表的主键GROUP BY而不需要在GROUP BY子句中添加该表的其他列的功能相对较新,并且仅适用于基表。优化器(还)不够聪明,无法识别视图、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 ;
Run Code Online (Sandbox Code Playgroud)
或使用子查询(并在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 ;
Run Code Online (Sandbox Code Playgroud)
也可以写成:
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 ;
Run Code Online (Sandbox Code Playgroud)
由于您使用的是 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 ;
Run Code Online (Sandbox Code Playgroud)