Errore Postgres [la colonna deve apparire nella clausola GROUP BY o deve essere utilizzata in una funzione aggregata] quando viene utilizzata una query secondaria


16

Ho due tavoli employeee phones. Un dipendente può avere da 0 a n numeri di telefono. Voglio elencare i nomi dei dipendenti con i loro numeri di telefono. Sto usando la query qui sotto che funziona bene.

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

inserisci qui la descrizione dell'immagine

La tabella dei dipendenti potrebbe contenere un numero elevato di righe. Voglio prendere solo alcuni impiegati alla volta. Ad esempio, voglio recuperare 3 dipendenti con i loro numeri di telefono. Sto cercando di eseguire questa query.

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

Ma ho questo errore. ERROR: column "employee.empname" must appear in the GROUP BY clause or be used in an aggregate function L'unica differenza tra due query è che sto usando una sub query in quest'ultima per limitare le righe prima di unirmi. Come posso risolvere questo errore?

Risposte:


21

La funzione di Postgres per poter usare la chiave primaria di una tabella con GROUP BYe non dover aggiungere le altre colonne di quella tabella nella GROUP BYclausola è relativamente nuova e funziona solo per le tabelle di base. L'ottimizzatore non è (ancora?) Abbastanza intelligente da identificare chiavi primarie per viste, cte o tabelle derivate (come nel tuo caso).

È possibile aggiungere le colonne che si desidera nella SELECTnella GROUP BYclausola:

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 ;

o usa una sottoquery (e trasferisci GROUP BYlì):

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 ;

che potrebbe anche essere scritto come:

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 ;

Dal momento che sei nella versione 9.3+. puoi anche usare un LATERALjoin:

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 Grazie. Questo è un modo semplice e pulito.
Programmatore
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.