Alt sorgu kullanıldığında postgres hatası [GROUP BY yan tümcesinde sütun görünmeli veya toplama işlevinde kullanılmalıdır]


17

İki masam var employeeve phones. Bir çalışan 0 ila n telefon numarasına sahip olabilir. Çalışan isimlerini telefon numaralarıyla listelemek istiyorum. İyi çalışan aşağıdaki sorguyu kullanıyorum.

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

resim açıklamasını buraya girin

Çalışan tablosu çok sayıda satır içerebilir. Bir seferde sadece bazı çalışanları almak istiyorum. Mesela 3 çalışanını telefon numaralarıyla getirmek istiyorum. Bu sorguyu çalıştırmaya çalışıyorum.

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

Ama bu hatayı alıyorum. ERROR: column "employee.empname" must appear in the GROUP BY clause or be used in an aggregate function İki sorgu arasındaki tek fark, katılmadan önce satırları sınırlamak için ikincisinde alt sorgu kullanarak olmasıdır. Bu hatayı nasıl çözebilirim?

Yanıtlar:


21

Postgres'ın tablonun birincil anahtarını kullanabilmesi ve GROUP BYbu tablonun diğer sütunlarını GROUP BYyan tümöre eklemesine gerek olmaması özelliği nispeten yenidir ve yalnızca temel tablolar için çalışır. Optimizer (henüz?) Görünümler, sandıklar veya türetilmiş tablolar için birincil anahtarları tanımlayacak kadar akıllı değildir (sizin durumunuzda olduğu gibi).

Sen de istediğiniz sütunları ekleyebilir SELECTiçine GROUP BYmaddesi:

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 ;

veya bir alt sorgu kullanın (ve GROUP BYorayı aktarın ):

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 ;

ayrıca şu şekilde de yazılabilir:

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+ sürümünde olduğunuz için. ayrıca bir LATERALbirleştirme kullanabilirsiniz :

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 Teşekkürler. Bu basit ve temiz bir yoldur.
Programcı
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.