ตรวจสอบว่ามีค่าอยู่ในอาร์เรย์ Postgres


196

ใช้ Postgres 9.0 ฉันต้องการวิธีทดสอบว่ามีค่าอยู่ในอาร์เรย์ที่กำหนดหรือไม่ จนถึงตอนนี้ฉันก็เกิดเรื่องแบบนี้ขึ้นมา:

select '{1,2,3}'::int[] @> (ARRAY[]::int[] || value_variable::int)

แต่ฉันคิดอยู่ตลอดว่าควรจะมีวิธีที่ง่ายกว่านี้ฉันแค่มองไม่เห็น ดูเหมือนว่าจะดีกว่า:

select '{1,2,3}'::int[] @> ARRAY[value_variable::int]

ฉันเชื่อว่ามันจะเพียงพอ แต่ถ้าคุณมีวิธีอื่นที่จะทำโปรดแบ่งปัน!

คำตอบ:


323

เรียบง่ายด้วยANYโครงสร้าง:

SELECT value_variable = ANY ('{1,2,3}'::int[])

ตัวถูกดำเนินการทางด้านขวาของANY(ระหว่างวงเล็บ) สามารถเป็นได้ทั้งชุด (ผลจากแบบสอบถามย่อยเป็นต้น)หรืออาร์เรย์ มีหลายวิธีในการใช้งาน:

สิ่งสำคัญที่แตกต่าง: ผู้ประกอบการอาร์เรย์ ( <@, @>, &&et al.)คาดว่าอาร์เรย์ชนิดเป็นตัวถูกดำเนินการและสนับสนุน GIN หรือดัชนีส่วนสำคัญในการจัดจำหน่ายมาตรฐานของ PostgreSQL ในขณะที่ANYสร้างคาดว่าจะมีองค์ประกอบชนิดเป็นตัวถูกดำเนินการด้านซ้ายและไม่สนับสนุนดัชนีเหล่านี้ ตัวอย่าง:

สิ่งนี้ไม่ได้ผลกับNULLองค์ประกอบ วิธีทดสอบNULL:


ขอบคุณ ต้องข้ามส่วนนั้นไปด้วยตนเอง มันใช้งานได้ดี มันมีผลข้างเคียงของการหล่ออัตโนมัติ เช่นเลือก 1 :: smallint = ANY ('{1,2,3}' :: int []) เพียงตรวจสอบให้แน่ใจว่าได้ใส่ ANY () ทางด้านขวาของนิพจน์
Mike Starov

ขอบคุณสำหรับคำตอบ. มีปัญหาเมื่อแบบสอบถามของฉันทำงานในท้องถิ่น แต่ใน heroku กำลังส่งข้อความนี้ANY/ALL (array) requires array on right sideการเพิ่ม::int[]เสน่ห์ได้ทำ
kinduff

โดยที่ S.employee_id <@ ANY ('"+ employeeIDsArray +"' :: int []) สิ่งนี้ส่งคืน PSQLException: ข้อผิดพลาด: ค่ามิติที่ขาดหายไป
Ramprasad

3
แม้ว่านี่จะเป็นคำถามเกี่ยวกับไดโนเสาร์ในอินเทอร์เน็ตหลายปี แต่ผู้คนอย่างช้าๆอย่างฉันก็ควรที่จะตระหนักว่า'something' = ANY(some_array)สามารถใช้ในWHEREประโยคได้เช่นกัน ด้วยเหตุผลที่ Crom รู้จักกันเพียงอย่างเดียวฉันได้ใช้เวลาสี่ปีที่ผ่านมาคิดว่าฉันไม่สามารถใช้ตัวเปรียบเทียบแถวเรียงในWHEREประโยค วันเหล่านั้นหายไปแล้ว (ฉันถูกวางบนหัวของฉันเป็นเด็กดังนั้นอาจเป็นเพียงฉัน)
GT

1
@GT: ส่วนสำคัญของมัน: การแสดงออกใด ๆ ที่ booleanทำงานในWHEREข้อ - Crom เต็มใจ
Erwin Brandstetter

90

ระวังกับดักที่ฉันเข้าไป: เมื่อตรวจสอบว่าค่าบางอย่างไม่อยู่ในอาร์เรย์คุณไม่ควรทำ:

SELECT value_variable != ANY('{1,2,3}'::int[])

แต่ใช้

SELECT value_variable != ALL('{1,2,3}'::int[])

แทน.


2
ชนิดของค่าลบสองเท่า สังเกตการใช้ALLvsANY
vol7ron

43
SELECT NOT value_variable = ANY('{1,2,3}'::int[])อาจอ่านได้มากขึ้น
Bouda

28

แต่ถ้าคุณมีวิธีอื่นที่จะทำกรุณาแบ่งปัน

คุณสามารถเปรียบเทียบสองอาร์เรย์ หากค่าใด ๆ ในอาเรย์ด้านซ้ายทับซ้อนกันของค่าในอาเรย์ขวามันจะส่งกลับค่าจริง มันเป็นแฮ็ค แต่มันใช้งานได้ดี

SELECT '{1}'   && '{1,2,3}'::int[];  -- true
SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
SELECT '{4}'   && '{1,2,3}'::int[];  -- false
  • ในแบบสอบถามแรกและครั้งที่สองค่า1อยู่ในอาร์เรย์ที่ถูกต้อง
  • ขอให้สังเกตว่าแบบสอบถามที่สองคือtrueแม้ว่าค่า4ไม่ได้อยู่ในอาร์เรย์ที่เหมาะสม
  • สำหรับการสืบค้นที่สามไม่มีค่าใดในอาร์เรย์ซ้าย (เช่น, 4) ที่อยู่ในอาร์เรย์ที่ถูกต้องดังนั้นจึงส่งคืนfalse

ฉันจะค้นหาคอลัมน์จากตารางอื่นเพื่อให้มีค่าในอาร์เรย์ได้อย่างไร เช่นเลือก * จากเบียร์ที่ style_id ใน (เลือกค่ากำหนดจากผู้ใช้ที่ id = 1) จำกัด 1; style_id เป็นชนิดข้อมูลจำนวนเต็ม การตั้งค่าเป็นจำนวนเต็ม [] ฉันได้รับข้อผิดพลาดนี้ข้อผิดพลาด: ไม่มีตัวดำเนินการ: จำนวนเต็ม = จำนวนเต็ม [] บรรทัดที่ 1: เลือก * จากเบียร์ที่ style_id ใน (การตั้งค่าเลือก f ... ^ คำแนะนำ: ไม่มีตัวดำเนินการตรงกับชื่อและประเภทอาร์กิวเมนต์ที่กำหนด (s). คุณอาจต้องเพิ่ม
HP

@HP มีวิธีการที่แตกต่างกันในการแก้คำถามนั้นคุณควรถามคำถามใหม่
vol7ron

คุณแน่ใจหรือว่าไม่มีคำถามที่มีอยู่ @ vol7ron
HP

@HP ไม่เป็นไร แต่ความคิดเห็นมีไว้สำหรับความคิดเห็นที่เกี่ยวข้องกับคำถามหรือคำตอบ โดยทั่วไปแล้วจะเพิ่มข้อมูลเพิ่มเติมหรือขอข้อมูลเพิ่มเติมที่ไม่ได้ระบุไว้ คุณกำลังถามคำถามที่ไม่เกี่ยวข้องกับคำตอบนี้ ฉันคิดว่าคุณจะมีโชคมากขึ้นโดยการถามคำถามของคุณเป็นโพสต์ใหม่ไม่ใช่ในความคิดเห็น;)
vol7ron

@HP หากคุณยังไม่ได้โพสต์คำถามคุณสามารถดูได้ที่นี่: sqlfiddle.com/#!15/144cd/3สำหรับตัวอย่างของสิ่งที่คุณต้องทำ - ปัญหาของคุณนั้นแตกต่างออกไป
vol7ron

4

unnestสามารถใช้เช่นกัน มันขยายอาร์เรย์ชุดของแถวแล้วก็ตรวจสอบค่าที่มีอยู่หรือไม่เป็นเรื่องง่ายเหมือนการใช้หรือINNOT IN

เช่น

  1. id => uuid

  2. exception_list_ids => uuid []

select * from table where id NOT IN (select unnest(exception_list_ids) from table2)


ใช่. โปรดทราบว่าในแบบสอบถามแผนของฉันเลือก UNNEST ไม่ดีเท่า = ใด ๆ ฉันขอแนะนำให้ตรวจสอบแผนแบบสอบถามเพื่อดูว่าคุณได้รับสิ่งที่คุณต้องการ / คาดหวังหรือไม่
Rob Bygrave

3

เมื่อมองหาการมีอยู่ขององค์ประกอบในอาเรย์จำเป็นต้องใช้การคัดเลือกที่เหมาะสมเพื่อส่งตัวแยกวิเคราะห์ SQL ของ postgres นี่คือตัวอย่างแบบสอบถามหนึ่งรายการที่ใช้อาร์เรย์มีตัวดำเนินการในส่วนคำสั่งการรวม:

เพื่อความง่ายฉันจะแสดงเฉพาะส่วนที่เกี่ยวข้องเท่านั้น:

table1 other_name text[]; -- is an array of text

ส่วนเข้าร่วมของ SQL ที่แสดง

from table1 t1 join table2 t2 on t1.other_name::text[] @> ARRAY[t2.panel::text]

ต่อไปนี้ยังใช้งานได้

on t2.panel = ANY(t1.other_name)

ฉันแค่คาดเดาว่าจำเป็นต้องใช้การร่ายพิเศษเนื่องจากการแยกวิเคราะห์ไม่จำเป็นต้องดึงคำจำกัดความของตารางเพื่อให้ได้ชนิดคอลัมน์ที่แน่นอน อื่น ๆ โปรดแสดงความคิดเห็นเกี่ยวกับเรื่องนี้


1

สวัสดีที่ทำงานได้ดีสำหรับฉันอาจจะมีประโยชน์สำหรับใครบางคน

เลือก * จาก your_table โดยที่ array_column :: text ilike ANY (ARRAY ['% text_to_search%' :: text]);

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