Но второй вариант каждого не эквивалентен другому. Второй вариант ANYконструкции принимает массив (должен быть фактическим типом массива), а второй вариант INпринимает список значений, разделенных запятыми . Это приводит к различным ограничениям на передачу значений, а также может привести к различным планам запросов в особых случаях:
Инверсия: «Найти строки , в которых idявляется не в массиве»:
SELECT*FROM tbl WHERE id <>ALL(ARRAY[1,2]);SELECT*FROM tbl WHERE id <>ALL('{1, 2}');-- equivalent array literalSELECT*FROM tbl WHERENOT(id =ANY('{1, 2}'));
Все три равнозначны. Первый с конструктором массива , два других с литералом массива . Тип данных может быть однозначно получен из контекста. В противном случае может потребоваться явное приведение, например'{1,2}'::int[] .
Строки с id IS NULLне проходят ни одно из этих выражений. Чтобы добавить NULLзначения дополнительно:
Было бы неплохо прямо уточнить, что результаты второго варианта всегда будут одинаковыми. Я на 99% уверен, что это действительно так, но ответ, похоже, не говорит об этом. Это означает, что SELECT * from mytable where id in (1, 2, 3)всегда будут те же строки, что и SELECT * from mytable where id = ANY('{1, 2, 3}'), даже если у них потенциально могут быть разные планы запросов.
КПД
1
ANYнельзя комбинировать с !=оператором. Я не думаю, что это задокументировано, но select * from foo where id != ANY (ARRAY[1, 2])это не то же самое, что select * from foo where id NOT IN (1, 2). С другой стороны, select * from foo where NOT (id = ANY (ARRAY[1, 2]))работает как положено.
qris 07
1
@qris: ANYможно комбинировать с !=оператором. Но это еще не все. Я добавил главу выше. (Обратите внимание, что <>это оператор в стандартном SQL - хотя !=он также принят в Postgres.)
Эрвин Брандштеттер,
Как работает последняя версия, включающая NULLзначения? Будет ли WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;работать так же хорошо?
dvtan
1
@dvtan: (id = ...) IS NOT TRUEработает, потому что id = ...оценивает, только TRUEесли есть фактическое совпадение. Результаты FALSEили NULLпройдите наш тест. См. Stackoverflow.com/a/23767625/939860 . Добавленные вами тесты выражений для чего-то еще. Это было бы эквивалентноWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Эрвин Брандштеттер
3
Есть два очевидных момента, а также пункты другого ответа:
Они в точности эквивалентны при использовании подзапросов:
Ответы:
(Ни и
IN
неANY
является «оператором». «Конструкция» или «элемент синтаксиса».)По логике , цитируя мануал :
Но есть два варианта синтаксиса из
IN
и два вариантаANY
. Подробности:IN
взятие набора эквивалентно= ANY
взятию набора , как показано здесь:Но второй вариант каждого не эквивалентен другому. Второй вариант
ANY
конструкции принимает массив (должен быть фактическим типом массива), а второй вариантIN
принимает список значений, разделенных запятыми . Это приводит к различным ограничениям на передачу значений, а также может привести к различным планам запросов в особых случаях:=any()
но используется сin
ANY
более универсаленANY
Конструкция является гораздо более универсальным, так как он может быть объединен с различными операторами, а не только=
. Пример:Для большого количества значений предоставление набора лучше масштабируется для каждого:
Связанный:
Инверсия / противоположность / исключение
«Найти строки
id
в заданном массиве»:Инверсия: «Найти строки , в которых
id
является не в массиве»:Все три равнозначны. Первый с конструктором массива , два других с литералом массива . Тип данных может быть однозначно получен из контекста. В противном случае может потребоваться явное приведение, например
'{1,2}'::int[]
.Строки с
id IS NULL
не проходят ни одно из этих выражений. Чтобы добавитьNULL
значения дополнительно:источник
SELECT * from mytable where id in (1, 2, 3)
всегда будут те же строки, что иSELECT * from mytable where id = ANY('{1, 2, 3}')
, даже если у них потенциально могут быть разные планы запросов.ANY
нельзя комбинировать с!=
оператором. Я не думаю, что это задокументировано, ноselect * from foo where id != ANY (ARRAY[1, 2])
это не то же самое, чтоselect * from foo where id NOT IN (1, 2)
. С другой стороны,select * from foo where NOT (id = ANY (ARRAY[1, 2]))
работает как положено.ANY
можно комбинировать с!=
оператором. Но это еще не все. Я добавил главу выше. (Обратите внимание, что<>
это оператор в стандартном SQL - хотя!=
он также принят в Postgres.)NULL
значения? Будет лиWHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;
работать так же хорошо?(id = ...) IS NOT TRUE
работает, потому чтоid = ...
оценивает, толькоTRUE
если есть фактическое совпадение. РезультатыFALSE
илиNULL
пройдите наш тест. См. Stackoverflow.com/a/23767625/939860 . Добавленные вами тесты выражений для чего-то еще. Это было бы эквивалентноWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Есть два очевидных момента, а также пункты другого ответа:
Они в точности эквивалентны при использовании подзапросов:
С другой стороны:
Только
IN
оператор допускает простой список:Предположение, что они точно такие же, несколько раз ловило меня, когда я забывал, что
ANY
это не работает со списками.источник