IN против ЛЮБОГО оператора в PostgreSQL

121

В чем разница между IN и ANYоператором в PostgreSQL?
Рабочий механизм у обоих вроде одинаков. Кто-нибудь может объяснить это на примере?

MRG
источник
3
Возможный дубликат postgreSQL - in vs any
Вивек С.
Отвечает ли это на ваш вопрос? Разница между in и любыми операторами в sql
philipxy

Ответы:

159

(Ни и INне ANYявляется «оператором». «Конструкция» или «элемент синтаксиса».)

По логике , цитируя мануал :

INэквивалентно = ANY.

Но есть два варианта синтаксиса из INи два варианта ANY. Подробности:

IN взятие набора эквивалентно = ANYвзятию набора , как показано здесь:

Но второй вариант каждого не эквивалентен другому. Второй вариант ANYконструкции принимает массив (должен быть фактическим типом массива), а второй вариант INпринимает список значений, разделенных запятыми . Это приводит к различным ограничениям на передачу значений, а также может привести к различным планам запросов в особых случаях:

ANY более универсален

ANYКонструкция является гораздо более универсальным, так как он может быть объединен с различными операторами, а не только =. Пример:

SELECT 'foo' LIKE ANY('{FOO,bar,%oo%}');

Для большого количества значений предоставление набора лучше масштабируется для каждого:

Связанный:

Инверсия / противоположность / исключение

«Найти строки idв заданном массиве»:

SELECT * FROM tbl WHERE id = ANY (ARRAY[1, 2]);

Инверсия: «Найти строки , в которых idявляется не в массиве»:

SELECT * FROM tbl WHERE id <> ALL (ARRAY[1, 2]);
SELECT * FROM tbl WHERE id <> ALL ('{1, 2}');  -- equivalent array literal
SELECT * FROM tbl WHERE NOT (id = ANY ('{1, 2}'));

Все три равнозначны. Первый с конструктором массива , два других с литералом массива . Тип данных может быть однозначно получен из контекста. В противном случае может потребоваться явное приведение, например'{1,2}'::int[] .

Строки с id IS NULLне проходят ни одно из этих выражений. Чтобы добавить NULLзначения дополнительно:

SELECT * FROM tbl WHERE (id = ANY ('{1, 2}')) IS NOT TRUE;
Эрвин Брандштеттер
источник
4
Было бы неплохо прямо уточнить, что результаты второго варианта всегда будут одинаковыми. Я на 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

Есть два очевидных момента, а также пункты другого ответа:

  • Они в точности эквивалентны при использовании подзапросов:

    SELECT * FROM table
    WHERE column IN(subquery);
    
    SELECT * FROM table
    WHERE column = ANY(subquery);

С другой стороны:

  • Только INоператор допускает простой список:

    SELECT * FROM table
    WHERE column IN(… ,  , …);

Предположение, что они точно такие же, несколько раз ловило меня, когда я забывал, что ANYэто не работает со списками.

Manngo
источник