Kiểm tra xem giá trị có tồn tại trong mảng Postgres không


194

Sử dụng Postgres 9.0, tôi cần một cách để kiểm tra nếu một giá trị tồn tại trong một mảng nhất định. Cho đến nay tôi đã nghĩ ra một cái gì đó như thế này:

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

Nhưng tôi cứ nghĩ nên có một cách đơn giản hơn để làm điều này, tôi chỉ không thể nhìn thấy nó. Điều này có vẻ tốt hơn:

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

Tôi tin rằng nó sẽ đủ. Nhưng nếu bạn có những cách khác để làm điều đó, hãy chia sẻ!

Câu trả lời:


322

Đơn giản hơn với ANYcấu trúc:

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

Toán hạng bên phải của ANY(giữa các dấu ngoặc đơn) có thể là một tập hợp (ví dụ kết quả của truy vấn con) hoặc một mảng . Có một số cách để sử dụng nó:

Quan trọng sự khác biệt: (khai thác mảng <@, @>, &&et al.) Mong đợi mảng kiểu như toán hạng và hỗ trợ GIN hoặc chỉ số GIST trong việc phân phối tiêu chuẩn của PostgreSQL, trong khi ANYxây dựng hy vọng một yếu tố loại như trái toán hạng và không hỗ trợ các chỉ số này. Thí dụ:

Không ai trong số này làm việc cho NULLcác yếu tố. Để kiểm tra NULL:


Cảm ơn. Phải bỏ qua phần đó của hướng dẫn. Điều này làm việc tuyệt vời. Nó có tác dụng phụ của đúc tự động. Ví dụ: CHỌN 1 :: smallint = ANY ('{1,2,3}' :: int []) hoạt động. Chỉ cần đảm bảo đặt BẤT K (() ở bên phải của biểu thức.
Mike Starov

Cảm ơn câu trả lời. Có một vấn đề trong đó truy vấn của tôi hoạt động trên địa phương, nhưng trong heroku đã gửi thông điệp này ANY/ALL (array) requires array on right side, phần bổ sung ::int[]đã làm nên sự quyến rũ.
kinduff

trong đó S.employee_id <@ ANY ('"+ workerIDsArray +"' :: int []) Điều này trả về PSQLException: ERROR: giá trị thứ nguyên bị thiếu
Ramprasad

3
Mặc dù đây là một câu hỏi khủng long trong những năm qua internet, những người chậm chạp như tôi nên được biết rằng 'something' = ANY(some_array)cũng có thể được sử dụng trong một WHEREmệnh đề. Vì những lý do chỉ được biết đến với Crom, tôi đã dành bốn năm qua để nghĩ rằng tôi không thể sử dụng các bộ so sánh mảng trong WHEREcác mệnh đề. Những ngày đó đã qua rồi. (Tôi đã bị đánh rơi trên đầu khi còn nhỏ, vì vậy có lẽ đó chỉ là tôi).
GT.

1
@GT.: Ý chính của nó: bất kỳ boolean biểu thức nào hoạt động trong WHEREmệnh đề - Crom sẵn sàng.
Erwin Brandstetter

90

Cảnh giác với cái bẫy tôi mắc phải: Khi kiểm tra xem giá trị nào đó không có trong một mảng, bạn không nên làm:

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

nhưng sử dụng

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

thay thế.


2
Loại âm đôi; chú ý việc anh ta sử dụng ALLvsANY
vol7ron

43
SELECT NOT value_variable = ANY('{1,2,3}'::int[])có thể dễ đọc hơn
Ondřej Bouda

28

nhưng nếu bạn có những cách khác để làm điều đó hãy chia sẻ.

Bạn có thể so sánh hai mảng. Nếu bất kỳ giá trị nào trong mảng bên trái trùng với các giá trị trong mảng bên phải, thì nó trả về giá trị true. Đó là một loại tin tặc, nhưng nó hoạt động.

SELECT '{1}'   && '{1,2,3}'::int[];  -- true
SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
SELECT '{4}'   && '{1,2,3}'::int[];  -- false
  • Trong truy vấn thứ nhất và thứ hai, giá trị 1nằm trong mảng bên phải
  • Lưu ý rằng truy vấn thứ hai là true, mặc dù giá trị 4không được chứa trong mảng bên phải
  • Đối với truy vấn thứ ba, không có giá trị nào trong mảng bên trái (nghĩa là 4) nằm trong mảng bên phải, vì vậy nó trả vềfalse

Làm thế nào tôi có thể tìm kiếm một cột từ một bảng khác để có một giá trị trong mảng? ví dụ: chọn * từ các loại bia có style_id in (chọn tùy chọn từ người dùng trong đó id = 1) giới hạn 1; style_id là một kiểu dữ liệu số nguyên; Tùy chọn là số nguyên [] Tôi gặp lỗi này LRI: toán tử không tồn tại: số nguyên = số nguyên [] LINE 1: select * từ các loại bia có style_id in (chọn tùy chọn f ... ^ GỢI Ý: Không có toán tử nào khớp với tên và loại đối số đã cho (s). Bạn có thể cần thêm các loại phôi rõ ràng.
HP

@HP Có nhiều cách khác nhau để giải quyết câu hỏi đó, bạn nên đặt một câu hỏi mới
vol7ron

bạn có chắc là không có câu hỏi nào không? @ vol7ron
HP

@HP Hoàn toàn không, nhưng ý kiến ​​là cho ý kiến ​​liên quan đến một câu hỏi hoặc câu trả lời; thông thường để thêm thông tin hoặc thu hút thêm thông tin không được giải quyết. Bạn đang hỏi một câu hỏi không liên quan đến câu trả lời này. Tôi nghĩ bạn sẽ gặp nhiều may mắn hơn bằng cách đặt câu hỏi của bạn dưới dạng một bài đăng mới, không phải trong bình luận;)
vol7ron

@HP nếu bạn chưa đăng câu hỏi của mình, bạn có thể xem tại đây: sqlfiddle.com/#!15/144cd/3 để biết ví dụ về những gì bạn cần làm - vấn đề của bạn là khác nhau vì bạn cần hủy bỏ mảng của mình.
vol7ron

4

unnestcó thể được sử dụng là tốt. Nó mở rộng mảng thành một tập hợp các hàng và sau đó chỉ cần kiểm tra một giá trị tồn tại hay không đơn giản như sử dụng INhoặc NOT IN.

ví dụ

  1. id => uuid

  2. ngoại lệ_list_ids => uuid []

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


Đúng. Lưu ý rằng trong các kế hoạch truy vấn của tôi, CHỌN UNNEST không tốt bằng = BẤT K .. Tôi khuyên bạn nên kiểm tra các kế hoạch truy vấn để xem nếu bạn có được những gì bạn muốn / mong đợi.
Rob Bygrave

3

Khi tìm kiếm sự tồn tại của một phần tử trong một mảng, cần phải truyền đúng cách để vượt qua trình phân tích cú pháp SQL của postgres. Dưới đây là một ví dụ truy vấn sử dụng mảng chứa toán tử trong mệnh đề nối:

Để đơn giản tôi chỉ liệt kê phần có liên quan:

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

Phần tham gia của SQL được hiển thị

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

Sau đây cũng hoạt động

on t2.panel = ANY(t1.other_name)

Tôi chỉ đoán rằng việc truyền thêm là bắt buộc vì phân tích cú pháp không phải tìm nạp định nghĩa bảng để tìm ra loại chính xác của cột. Những người khác xin vui lòng bình luận về điều này.


0

Xin chào, một trong những hoạt động tốt cho tôi, có thể hữu ích cho ai đó

chọn * từ your_table trong đó mảng_column :: text ilike ANY (ARRAY ['% text_to_search%' :: text]);

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.