Postgres ไม่อยู่ในอาร์เรย์


100

ฉันใช้ประเภทอาร์เรย์เนทีฟของ Postgres และพยายามค้นหาเร็กคอร์ดที่ ID ไม่อยู่ใน ID ผู้รับอาร์เรย์

ฉันสามารถค้นหาว่าพวกเขาอยู่ที่ไหน:

SELECT COUNT(*) FROM messages WHERE (3 = ANY (recipient_ids))

แต่ไม่ได้ผล:

SELECT COUNT(*) FROM messages WHERE (3 != ANY (recipient_ids))
SELECT COUNT(*) FROM messages WHERE (3  = NOT ANY (recipient_ids))

วิธีที่ถูกต้องในการทดสอบเงื่อนไขนี้คืออะไร?


ไม่WHERE 3 NOT IN recipient_idsทำงานหรือไม่
Janus Troelsen

1
หมายเหตุที่เกี่ยวข้อง: สำหรับtext[]และint[]อาร์เรย์:select not(array[1,2,3] @> array[3]);
Steve Peak

3
Pro เคล็ดลับ: หากคุณกำลังตรวจสอบหากมีnullคอลัมน์ที่มีอยู่หรือไม่อยู่ในอาร์เรย์ก็จะมักจะบอกว่าไม่มี ฉันใช้เวลาประมาณ 20 นาทีในการดีบักวิธีการที่มีหลายวิธีเพื่อสรุปว่าคุณไม่สามารถตรวจสอบได้ว่ามี null อยู่ในอาร์เรย์หรือไม่
André Pena

คำตอบ:


139
SELECT COUNT(*) FROM "messages" WHERE NOT (3 = ANY (recipient_ids))

คุณสามารถลบล้างWHERE (condition)ด้วยWHERE NOT (condition)


2
@aschyiel - คุณอาจต้องการเปลี่ยนกลับไปANYแทนที่จะINเป็นเมื่อrecipient_idsรายการอินพุตของคุณเพิ่มขึ้น: stackoverflow.com/questions/1009706/…
derekm

41

คุณสามารถหมุนได้เล็กน้อยและพูดว่า "3 ไม่เท่ากับรหัสทั้งหมด":

where 3 != all (recipient_ids)

จากคู่มือที่ดี :

9.21.4. ทั้งหมด (อาร์เรย์)

expression operator ALL (array expression)

ด้านขวามือคือนิพจน์ในวงเล็บซึ่งต้องให้ค่าอาร์เรย์ นิพจน์ทางซ้ายได้รับการประเมินและเปรียบเทียบกับแต่ละองค์ประกอบของอาร์เรย์โดยใช้ตัวดำเนินการที่กำหนดซึ่งจะต้องให้ผลลัพธ์แบบบูลีน ผลลัพธ์ของALLคือ "จริง" หากการเปรียบเทียบทั้งหมดให้ผลเป็นจริง (รวมถึงกรณีที่อาร์เรย์มีองค์ประกอบเป็นศูนย์) ผลลัพธ์จะเป็น "เท็จ" หากพบผลลัพธ์ที่เป็นเท็จ


นี่ไม่ได้อธิบายจริงๆว่าทำไมanyไม่ทำงานในกรณีนี้
seanlinsley

สิ่งนี้ควรได้รับการยอมรับเนื่องจากอธิบายเหตุผลอย่างถูกต้อง ป.ล. คุณสามารถค้นหาanyและallในเอกสาร postgres ซึ่งระบุว่า: " x <> ANY (a,b,c) เทียบเท่ากับx <> a OR <> b OR x <> c" ref: postgresqltutorial.com/postgresql-any postgresqltutorial.com/postgresql-all
Tyler Temp

19

การเพิ่มALL/ANYคำตอบ

ฉันชอบวิธีแก้ปัญหาทั้งหมดที่ใช้allหรือanyเพื่อให้บรรลุผลลัพธ์ชื่นชมบันทึกเพิ่มเติม (เช่นเกี่ยวกับNULL s) ในฐานะผู้ให้บริการรายอื่นนี่คือวิธีคิดเกี่ยวกับตัวดำเนินการเหล่านั้น

คุณสามารถคิดว่าพวกเขาเป็นตัวดำเนินการไฟฟ้าลัดวงจร :

  • all(array)ส่งผ่านค่าทั้งหมดในอาร์เรย์โดยเปรียบเทียบกับค่าอ้างอิงโดยใช้ตัวดำเนินการที่ให้มา ทันทีที่การเปรียบเทียบให้ผลfalseกระบวนการจะจบลงด้วยเท็จหรือเป็นจริง (เทียบได้กับตรรกะการลัดวงจรand)
  • any(array)ส่งผ่านค่าทั้งหมดในอาร์เรย์โดยเปรียบเทียบกับค่าอ้างอิงโดยใช้ตัวดำเนินการที่ให้มา ทันทีที่ให้ผลการเปรียบเทียบtrueกระบวนการจะจบลงด้วยจริงหรือเป็นเท็จ (เทียบได้กับตรรกะการลัดวงจรor)

นี่คือเหตุผลที่3 <> any('{1,2,3}')ไม่ให้ผลลัพธ์ที่ต้องการ: กระบวนการเปรียบเทียบ 3 กับ 1 สำหรับอสมการซึ่งเป็นจริงและส่งกลับค่าจริงทันที ค่าเดียวในอาร์เรย์ที่แตกต่างจาก 3 ก็เพียงพอที่จะทำให้เงื่อนไขทั้งหมดเป็นจริง 3 ในตำแหน่งอาร์เรย์สุดท้ายคือพร็อบ ไม่เคยใช้.

3 <> all('{1,2,3}')ในทางกลับกันทำให้แน่ใจว่าค่าทั้งหมดไม่เท่ากัน 3 มันจะทำงานผ่านการเปรียบเทียบทั้งหมดที่ให้ผลเป็นจริงจนถึงองค์ประกอบที่ให้ผลเป็นเท็จ (ค่าสุดท้ายในกรณีนี้) เพื่อส่งคืนค่าเท็จเป็นผลลัพธ์โดยรวม นี่คือสิ่งที่ OP ต้องการ




12

ระวัง NULL

ทั้งสองALL:

(some_value != ALL(some_array))

และANY:

NOT (some_value = ANY(some_array))

จะทำงานได้ตราบเท่าที่some_arrayไม่เป็นโมฆะ ถ้าอาร์เรย์อาจเป็นโมฆะคุณต้องพิจารณาด้วย coalesce () เช่น

(some_value != ALL(coalesce(some_array, array[]::int[])))

หรือ

NOT (some_value = ANY(coalesce(some_array, array[]::int[])))

จากเอกสาร :

หากนิพจน์อาร์เรย์ให้ผลลัพธ์อาร์เรย์ว่างผลลัพธ์ของ ANY จะเป็นค่าว่าง

หากนิพจน์อาร์เรย์ให้ผลลัพธ์อาร์เรย์ว่างผลลัพธ์ของ ALL จะเป็นค่าว่าง


3

โปรดทราบว่าตัวดำเนินการใด ๆ / ทั้งหมดจะไม่ทำงานกับดัชนีอาร์เรย์ หากดัชนีอยู่ในใจ:

SELECT COUNT(*) FROM "messages" WHERE 3 && recipient_ids

และเชิงลบ:

SELECT COUNT(*) FROM "messages" WHERE NOT (3 && recipient_ids)

จากนั้นสามารถสร้างดัชนีได้เช่น:

CREATE INDEX recipient_ids_idx on tableName USING GIN(recipient_ids)

ไม่เหมือนกับคำตอบอื่น ๆ คำตอบนี้ใช้ประโยชน์จากตัวดำเนินการซ้อนทับอาร์เรย์ของ PostgreSQL &&
Ceiling Gecko

6
สิ่งนี้จะไม่ทำงานตามที่เขียนไว้ ตัวดำเนินการอาร์เรย์เช่น && และ @> กำหนดให้องค์ประกอบทั้งสองเป็นอาร์เรย์ซึ่ง 3 ไม่ใช่ SELECT COUNT(*) FROM "messages" WHERE ARRAY[3] && recipient_idsในการสั่งซื้อสำหรับการทำงานแบบสอบถามจะต้องมีการเขียนเป็น:
Dologan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.