ข้อผิดพลาด Postgres [คอลัมน์จะต้องปรากฏในกลุ่มตามข้อหรือใช้ในฟังก์ชั่นรวม] เมื่อใช้แบบสอบถามย่อย


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 BYclause นั้นค่อนข้างใหม่และใช้ได้กับตารางฐานเท่านั้น เครื่องมือเพิ่มประสิทธิภาพยังไม่ฉลาดพอที่จะระบุคีย์หลักสำหรับมุมมอง 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 ;

@percude ขอบคุณ นี่เป็นวิธีที่ง่ายและสะอาด
โปรแกรมเมอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.