J'ai deux tables employee
et phones
. Un employé peut avoir de 0 à n numéros de téléphone. Je veux lister les noms des employés avec leurs numéros de téléphone. J'utilise la requête ci-dessous qui fonctionne bien.
SELECT empname,array_agg(phonenumber) AS phonenumbers
FROM employee LEFT OUTER JOIN phones ON employee.empid = phones.empid
GROUP BY employee.empid
La table des employés peut contenir un grand nombre de lignes. Je souhaite récupérer uniquement certains employés à la fois. Par exemple, je veux récupérer 3 employés avec leurs numéros de téléphone. J'essaie d'exécuter cette requête.
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
Mais je reçois cette erreur. ERROR: column "employee.empname" must appear in the GROUP BY clause or be used in an aggregate function
La seule différence entre deux requêtes est que j'utilise une sous-requête dans cette dernière pour limiter les lignes avant de rejoindre. Comment résoudre cette erreur?
La fonctionnalité de Postgres pour pouvoir utiliser la clé primaire d'une table avec GROUP BY
Et ne pas avoir besoin d'ajouter les autres colonnes de cette table dans la clause GROUP BY
Est relativement nouvelle et ne fonctionne que pour la base les tables. L'optimiseur n'est pas (encore?) Assez intelligent pour identifier les clés primaires des vues, des ctes ou des tables dérivées (comme dans votre cas).
Vous pouvez ajouter les colonnes souhaitées dans la SELECT
dans la clause 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 ;
ou utilisez une sous-requête (et transférez-y le 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 ;
qui pourrait également s'écrire:
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 ;
Puisque vous êtes dans la version 9.3+. vous pouvez également utiliser une jointure 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 ;