Проверить, существует ли значение в массиве Postgres

209

Используя Postgres 9.0, мне нужен способ проверить, существует ли значение в данном массиве. Пока что я придумал что-то вроде этого:

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

Но я продолжаю думать, что должен быть способ попроще, я просто не вижу этого. Кажется, лучше:

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

Я думаю, этого будет достаточно. Но если у вас есть другие способы сделать это, поделитесь, пожалуйста!

Майк Старов
источник

Ответы:

344

Проще с 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[]сделало шарм.
kinduff
где S.employee_id <@ ANY ('"+ employeeIDsArray +"' :: int []) Это возвращает PSQLException: ОШИБКА: отсутствует значение измерения
Ramprasad
3
Хотя в годы Интернета это вопрос динозавров, медлительным людям вроде меня следует знать, что 'something' = ANY(some_array)это также может быть использовано в WHEREпредложении. По причинам, известным только Крому, последние четыре года я думал, что не могу использовать компараторы массивов в WHEREпредложениях. Те дни прошли. (В детстве меня уронили на голову, может, это только я).
GT.
1
@GT .: Суть: любое boolean выражение работает в WHEREпредложении - Кром желает.
Эрвин Брандштеттер
97

Остерегайтесь ловушки, в которую я попал: при проверке отсутствия определенного значения в массиве делать не следует:

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

но используйте

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

вместо.

Мурисон
источник
3
Вид двойного негатива; обратите внимание на его использование ALLvsANY
vol7ron
44
SELECT NOT value_variable = ANY('{1,2,3}'::int[])может быть более читаемым
Ondřej Bouda
32

но если у вас есть другие способы сделать это, поделитесь.

Вы можете сравнить два массива. Если какое-либо из значений в левом массиве перекрывает значения в правом массиве, возвращается значение true. Это вроде хакерство, но работает.

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
vol7ron
источник
как я могу найти столбец из другой таблицы, чтобы иметь значение в массиве? например, выберите * из пива, где style_id в (выберите предпочтения пользователей, где id = 1), ограничение 1; style_id - это целочисленный тип данных; предпочтения - целое число [] Я получаю эту ошибку ОШИБКА: оператор не существует: целое число = целое число [] СТРОКА 1: выберите * из пива, где style_id в (выберите предпочтения f ... ^ ПОДСКАЗКА: ни один оператор не соответствует заданному имени и типу аргумента (s). Возможно, вам потребуется добавить явное приведение типов.
HP,
@HP Есть разные способы решить этот вопрос, вам следует задать новый вопрос
vol7ron
Вы уверены, что вопросов нет? @ vol7ron
HP
@HP Вовсе нет, но комментарии предназначены для комментариев, касающихся вопроса или ответа; обычно для добавления дополнительной информации или запроса дополнительной информации, которая не была рассмотрена. Вы задаете вопрос, не связанный с этим ответом. Думаю, вам повезет больше, если вы
зададите
@HP, если вы еще не разместили свой вопрос, вы можете увидеть здесь: sqlfiddle.com/#!15/144cd/3, где приведен пример того, что вам нужно сделать - ваша проблема в другом, потому что вам нужно разложить массив.
vol7ron
4

unnestтакже можно использовать. Он расширяет массив до набора строк, а затем просто проверять, существует ли значение или нет, так же просто, как использовать INили NOT IN.

например

  1. id => uuid

  2. exception_list_ids => uuid []

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

pg2286
источник
Да. Обратите внимание, что в моих планах запросов SELECT UNNEST не так хорош, как = ANY. Я бы рекомендовал проверить планы запросов, чтобы узнать, получили ли вы то, что хотите / ожидаете.
Роб Бигрейв
3

При поиске наличия элемента в массиве требуется правильное приведение для передачи синтаксическому анализатору SQL postgres. Вот один пример запроса с использованием оператора array contains в предложении соединения:

Для простоты я перечисляю только соответствующую часть:

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)

Я просто предполагаю, что требуется дополнительное приведение, потому что синтаксическому анализу не нужно извлекать определение таблицы, чтобы определить точный тип столбца. Другие, пожалуйста, прокомментируйте это.

Кемин Чжоу
источник
2

Привет, у меня отлично работает, может быть, кому-то пригодится

select * from your_table where array_column ::text ilike ANY (ARRAY['%text_to_search%'::text]);
Дэйв Крацо
источник
0

«Любой» работает хорошо. Просто убедитесь, что ключевое слово any находится справа от знака равенства, т.е. стоит после знака равенства.

Приведенный ниже оператор вызовет ошибку: ОШИБКА: синтаксическая ошибка рядом с "любым"

select 1 where any('{hello}'::text[]) = 'hello';

В то время как ниже пример работает нормально

select 1 where 'hello' = any('{hello}'::text[]);
Дебасиш Митра
источник