Error de Postgres [la columna debe aparecer en la cláusula GROUP BY o usarse en una función agregada] cuando se usa la subconsulta


16

Tengo dos mesas employeey phones. Un empleado puede tener 0 a n números de teléfono. Quiero enumerar los nombres de los empleados con sus números de teléfono. Estoy usando la siguiente consulta que funciona bien.

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

ingrese la descripción de la imagen aquí

La tabla de empleados puede contener un gran número de filas. Quiero buscar solo algunos empleados a la vez. Por ejemplo, quiero buscar a 3 empleados con sus números de teléfono. Estoy tratando de ejecutar esta consulta.

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

Pero me sale este error. ERROR: column "employee.empname" must appear in the GROUP BY clause or be used in an aggregate function La única diferencia entre dos consultas es que estoy usando subconsulta en la última para limitar las filas antes de unirme. ¿Cómo resuelvo este error?

Respuestas:


21

La característica de Postgres para poder usar la clave primaria de una tabla GROUP BYy no tener que agregar las otras columnas de esa tabla en la GROUP BYcláusula es relativamente nueva y funciona solo para las tablas base. El optimizador no es (¿todavía?) Lo suficientemente inteligente como para identificar claves principales para vistas, ctes o tablas derivadas (como en su caso).

Puede agregar las columnas que desee en SELECTla GROUP BYcláusula:

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 use una subconsulta (y transfiera la GROUP BYallí):

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 ;

que también podría escribirse como:

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 ;

Ya que estás en la versión 9.3+. También puedes usar una LATERALcombinación:

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 Gracias. Esta es una manera simple y limpia.
Programador del
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.