Перевірте, чи існує значення в масиві 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(між дужками) може бути або набором (наприклад, підзапитом), або масивом . Існує кілька способів його використання:

Важливе відмінність: (Array оператори <@, @>, &&. І ін) очікують масив типів в якості операндів і підтримки GIN або індексів GiST в стандартному розподілі PostgreSQL, в той час як ANYконструкція очікує елемент типу як лівий операнд і не підтримують ці показники. Приклад:

Ніщо з цього не працює для NULLелементів. Для тестування на NULL:


Дякую. Повинен пропустити цю частину посібника. Це чудово працює. Він має побічний ефект автоматичного лиття. Наприклад: SELECT 1 :: smallint = ANY ('{1,2,3}' :: int [] працює). Просто переконайтеся, що БУДЬ-небудь () справа на виразі.
Майк Старов

Дякую за відповідь. У мене виникла проблема, коли мій запит працював над локальними, але в heroku кидали це повідомлення ANY/ALL (array) requires array on right side, додаток ::int[]зробив чарівність.
киндуф

де S.employee_id <@ ANY ('"+ службовий IDsArray +"' :: int []) Це повертає PSQLException: ПОМИЛКА: відсутнє значення розміру
Ramprasad

3
Хоча це питання динозавра в Інтернеті, повільним людям, як я, слід усвідомлювати, що 'something' = ANY(some_array)їх також можна використовувати в WHEREпункті. З причин, відомих лише Crom, я провів останні чотири роки, думаючи, що не можу використовувати компаратори масивів у WHEREпунктах. Зараз минули ці дні. (Мене впали на голову ще в дитинстві, тому, можливо, це я тільки).
GT.

1
@GT.: Суть цього: будь-який boolean вираз працює в WHEREпункті - Crom готовий.
Ервін Брандстеттер

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[])може бути читабельнішим
Ондржей Буда

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 - цілий тип даних; preferences integer [] Я отримую цю помилку ПОМИЛКА: оператор не існує: integer = integer [] LINE 1: select * from piers where style_id in (select preferences f ... ^ Підказка: жоден оператор не відповідає вказаному імені та типу аргументу Можливо, вам потрібно буде додати чіткі касти в тип
HP

@HP Є різні способи вирішити це питання, вам слід задати нове запитання
vol7ron

Ви впевнені, що немає жодного питання? @ vol7ron
HP

@HP Зовсім не, але коментарі - це коментарі щодо запитання чи відповіді; як правило, щоб додати більше інформації або вимагати більше інформації, яка не була адресована. Ви ставите запитання, яке не пов'язане з цією відповіддю. Думаю, вам пощастить, задавши своє запитання як новій публікації, а не в коментарі;)
vol7ron

@HP Якщо ви не розмістили запитання, ви можете ознайомитись тут: sqlfiddle.com/#!15/144cd/3 із прикладом того, що вам потрібно зробити - ваша проблема відрізняється тим, що вам потрібно зняти масив.
vol7ron

4

unnestможна також використовувати. Він розширює масив до набору рядків, а потім просто перевірити існування значення чи не так просто, як використання INабо NOT IN.

напр

  1. id => uuid

  2. виключення_list_ids => uuid []

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


Так. Зауважте, що в моїх планах запитів SELECT UNNEST не так добре, як = БУДЬ-ЯКЕ. Я рекомендую перевірити плани запитів, щоб побачити, чи отримуєте ви те, що хочете / очікуєте.
Роб Біграйв

3

Шукаючи наявність елемента в масиві, для передачі SQL-аналізатора постгресів потрібна відповідна кастинг. Ось один приклад запиту за допомогою масиву містить оператора в пункті приєднання:

Для простоти я перелічу лише відповідну частину:

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

Привіт, що для мене добре працює, може бути корисно для когось

виберіть * зі свого_таблиці, де array_column :: text ilike ANY (ARRAY ['% text_to_search%' :: text]);

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.