Помилка Postgres [стовпець повинен з'являтися в пункті GROUP BY або використовуватись у сукупності функції], коли використовується підзапит


17

У мене дві таблиці 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 Єдина відмінність двох запитів полягає в тому, що я використовую підзапроси в останньому для обмеження рядків перед приєднанням. Як вирішити цю помилку?

Відповіді:


21

Особливість 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 ;

або використовувати підзапит (і перенести 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 Дякую Це простий і чистий спосіб.
програміст
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.