Postgres НЕ в масиві


96

Я використовую рідний тип масиву Postgres і намагаюся знайти записи, де ідентифікатора немає в ідентифікаторах одержувача масиву.

Я можу знайти, де вони знаходяться:

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роботу?
Янус Трольсен

1
Родинне примітка: за text[]і int[]масив:select not(array[1,2,3] @> array[3]);
Стів Пік

3
Порада професіонала: якщо ви перевіряєте, чи nullстовпець міститься в масиві чи ні, він завжди буде відповідати « ні». Мені знадобилося 20 хвилин налагодження декількох методів, що містять, щоб прийти до висновку, що ви не можете перевірити, чи містить null масив
Андре Пена,

Відповіді:



39

Ви можете трохи повернути його і сказати "3 не дорівнює всім ідентифікаторам":

where 3 != all (recipient_ids)

З чудового посібника :

9.21.4. ALL (масив)

expression operator ALL (array expression)

Права частина - це вираз у дужках, який повинен давати значення масиву. Лівий вираз обчислюється і порівнюється з кожним елементом масиву за допомогою заданого оператора , який повинен дати булевий результат. Результат ALL"true", якщо всі порівняння дають true (включаючи випадок, коли масив містить нуль елементів). Результат буде "помилковим", якщо буде знайдено якийсь помилковий результат.


це насправді не пояснює, чому anyв даному випадку це не спрацьовує
Seanlinsley

Це слід прийняти, оскільки воно належним чином пояснило причину. PS ви також можете знайти anyі allна postgres doc, де сказано: " x <> ANY (a,b,c) еквівалентно x <> a OR <> b OR x <> c". ref: postgresqltutorial.com/postgresql-any postgresqltutorial.com/postgresql-all
Тайлер Темп

19

Доповнення ALL/ANYвідповідей

Я віддаю перевагу всім рішенням, які використовують allабо anyдля досягнення результату, оцінюючи додаткові примітки (наприклад, про NULL ). Як чергове доповнення, ось спосіб подумати про цих операторів.

Ви можете думати про них як про операторів короткого замикання :

  • all(array)проходить через усі значення в масиві, порівнюючи кожне з еталонним значенням, використовуючи наданий оператор. Як тільки порівняння дає результат false, процес закінчується помилковим, інакше істинним. (Порівняно з логічним замиканням and.)
  • any(array)проходить через усі значення в масиві, порівнюючи кожне з еталонним значенням за допомогою наданого оператора. Як тільки порівняння дає результат true, процес закінчується істиною, інакше помилкою. (Порівняно з логічним замиканням or.)

Ось чому 3 <> any('{1,2,3}')не дає бажаного результату: процес порівнює 3 з 1 для нерівності, що відповідає дійсності, і негайно повертає істину. Одного значення в масиві, відмінному від 3, достатньо, щоб зробити усю умову істинною. Значення 3 в останньому положенні масиву - prob. ніколи не використовували.

3 <> all('{1,2,3}')з іншого боку, переконує, що всі значення не рівні 3. Він буде проходити всі порівняння, що дають true, аж до елемента, який дає false (останнє в даному випадку), щоб повернути false як загальний результат. Цього хоче ОП.




11

Остерігайтеся НУЛЬ

Обидва 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

Зверніть увагу, що оператори ANY / ALL не працюватимуть з індексами масивів. Якщо маються на увазі індекси:

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. &&
Стельовий геккон

6
Це не буде працювати, як написано. Оператори масивів, такі як && та @>, вимагають, щоб обидва елементи були масивами, а 3 - ні. Для того , щоб це працювало, то запит буде необхідно записати в виде: SELECT COUNT(*) FROM "messages" WHERE ARRAY[3] && recipient_ids.
Дологан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.