Postgres KHÔNG trong mảng


96

Tôi đang sử dụng kiểu mảng gốc của Postgres và cố gắng tìm các bản ghi mà ID không có trong ID người nhận mảng.

Tôi có thể tìm thấy họ đang ở đâu:

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

Nhưng điều này không hoạt động:

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

Cách phù hợp để kiểm tra tình trạng này là gì?


không WHERE 3 NOT IN recipient_idshoạt động?
Janus Troelsen,

1
Ghi chú liên quan: như cho text[]int[]mảng:select not(array[1,2,3] @> array[3]);
Steve Peak

3
Mẹo chuyên nghiệp: Nếu bạn đang kiểm tra xem một nullcột được chứa hay không được chứa trong một mảng, nó sẽ luôn nói không. Phải mất tôi như 20 phút gỡ lỗi một số phương pháp có chứa để đi đến kết luận rằng bạn không thể kiểm tra nếu null được chứa trong một mảng
André Pena

Câu trả lời:


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

Bạn luôn có thể phủ định WHERE (condition)vớiWHERE NOT (condition)


2
@aschyiel - Bạn có thể muốn chuyển về ANYthay vì INnhư bạn recipient_idsdanh sách đầu vào phát triển: stackoverflow.com/questions/1009706/...
derekm

39

Bạn có thể xoay ngược nó một chút và nói "3 không bằng tất cả các ID":

where 3 != all (recipient_ids)

Từ hướng dẫn sử dụng tốt :

9.21.4. TẤT CẢ (mảng)

expression operator ALL (array expression)

Phía bên tay phải là một biểu thức có dấu ngoặc đơn, phải mang lại một giá trị mảng. Biểu thức bên trái được đánh giá và so sánh với từng phần tử của mảng bằng toán tử đã cho , toán tử này phải mang lại kết quả Boolean. Kết quả của ALLlà "true" nếu tất cả các phép so sánh đều trả về true (kể cả trường hợp mảng không có phần tử nào). Kết quả là "false" nếu tìm thấy bất kỳ kết quả sai nào.


điều này không thực sự giải thích tại sao anykhông làm việc trong trường hợp này
seanlinsley

Điều này nên được chấp nhận vì nó đã giải thích lý do hợp lý. PS bạn cũng có thể tìm anyalltrên postgres doc, mà nói: " x <> ANY (a,b,c) tương đương với x <> a OR <> b OR x <> c". ref: postgresqltutorial.com/postgresql-any postgresqltutorial.com/postgresql-all
Tyler Temp vào

19

Bổ sung ALL/ANYcâu trả lời

Tôi thích tất cả các giải pháp sử dụng allhoặc anyđể đạt được kết quả, đánh giá cao các ghi chú bổ sung (ví dụ: về NULL s). Đây là một cách để suy nghĩ về các toán tử đó.

Bạn có thể nghĩ về chúng như là các toán tử ngắn mạch :

  • all(array)đi qua tất cả các giá trị trong mảng, so sánh từng giá trị với giá trị tham chiếu bằng cách sử dụng toán tử được cung cấp. Ngay khi kết quả so sánh false, quá trình kết thúc bằng false, ngược lại là true. (So ​​sánh với logic ngắn mạch and.)
  • any(array)đi qua tất cả các giá trị trong mảng, so sánh từng giá trị với giá trị tham chiếu bằng cách sử dụng toán tử được cung cấp. Ngay khi kết quả so sánh true, quá trình kết thúc với true, ngược lại là false. (So ​​sánh với logic ngắn mạch or.)

Đây là lý do tại sao 3 <> any('{1,2,3}')không mang lại kết quả mong muốn: Quá trình so sánh 3 với 1 cho bất đẳng thức, là true, và ngay lập tức trả về true. Một giá trị duy nhất trong mảng khác với 3 là đủ để làm cho toàn bộ điều kiện đúng. 3 ở vị trí mảng cuối cùng là giá trị thử nghiệm. không bao giờ được sử dụng.

3 <> all('{1,2,3}')mặt khác đảm bảo rằng tất cả các giá trị không bằng nhau 3. Nó sẽ chạy qua tất cả các phép so sánh mang lại giá trị true cho đến một phần tử cho kết quả false (cuối cùng trong trường hợp này), để trả về false dưới dạng kết quả tổng thể. Đây là những gì OP muốn.


12

not (3 = any(recipient_ids))?


Cảm ơn, tôi đã sử dụng 3 <> ANY(ARRAY[1,2,3,4]). Nó đáng lẽ phải hoạt động theo cách đó: \
yeyo

11

một bản cập nhật:

kể từ postgres 9.3,

bạn có thể sử dụng NOTsong song với @> (hàm chứa) để đạt được điều này.

I E.

SELECT COUNT(*) FROM "messages" WHERE NOT recipient_ids @> ARRAY[3];


11

Cẩn thận với NULL

Cả hai ALL:

(some_value != ALL(some_array))

ANY:

NOT (some_value = ANY(some_array))

Sẽ hoạt động miễn some_arraylà không rỗng. Nếu mảng có thể là null, thì bạn phải giải thích nó bằng thanesce (), ví dụ:

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

Hoặc là

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

Từ các tài liệu :

Nếu biểu thức mảng cho ra một mảng rỗng, kết quả của BẤT KỲ sẽ là giá trị rỗng

Nếu biểu thức mảng cho ra một mảng rỗng, kết quả của TẤT CẢ sẽ là giá trị rỗng


3

Lưu ý rằng các toán tử BẤT KỲ / TẤT CẢ sẽ không hoạt động với chỉ mục mảng. Nếu các chỉ mục được ghi nhớ:

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

và phủ định:

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

Một chỉ mục sau đó có thể được tạo như:

CREATE INDEX recipient_ids_idx on tableName USING GIN(recipient_ids)

Không giống như các câu trả lời khác, câu trả lời này thực sự sử dụng toán tử chồng chéo mảng PostgreSQL. &&
Ceiling Gecko

6
Điều này sẽ không hoạt động như đã viết. Các toán tử mảng như && và @> yêu cầu cả hai phần tử phải là mảng, 3 thì không. Để cho tiện làm việc, truy vấn sẽ cần phải được viết như sau: SELECT COUNT(*) FROM "messages" WHERE ARRAY[3] && recipient_ids.
Dologan
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.