IN
DSQL, PSQL, ESQL.
<value> [NOT] IN (<select_stmt> | <value_list>) <value_list> ::= <value_1> [, <value_2> ...]
Предикат IN
проверяет, присутствует ли значение выражения слева в указанном справа наборе значений.Набор значений не может превышать 1500 элементов.Предикат IN
может быть переписан в следующей эквивалентной форме:
(<value> = <value_1> [OR <value> = <value_2> ...])
При использовании предиката IN
в поисковых условиях DML запросов, оптимизатор Firebird может использовать индекс по искомому столбцу, если он определён.
Во второй форме предикат IN
проверяет, присутствует (или отсутствует, при использовании NOT IN
) ли значение выражения слева в результате выполнения подзапроса справа.Результат подзапроса может содержать только один столбец, иначе будет выдана ошибка“count of column list and variable list do not match”.
Запросы с использованием предиката IN
с подзапросом, можно переписать на аналогичный запрос с использованием предиката EXISTS
.Например, следующий запрос:
SELECT
model, speed, hd
FROM PC
WHERE
model IN (SELECT model
FROM product
WHERE maker = 'A');
Можно переписать на аналогичный запрос с использованием предиката EXISTS
:
SELECT
model, speed, hd
FROM PC
WHERE
EXISTS (SELECT *
FROM product
WHERE maker = 'A'
AND product.model = PC.model);
Однако, запрос с использованием NOT IN
не всегда даст тот же результат, что запрос NOT EXISTS
.Причина заключается в том, что предикат EXISTS
всегда возвращает TRUE
или FALSE
, тогда как предикат IN
может вернуть NULL
в следующих случаях:
-
Когда проверяемое значение равно
NULL
и список вIN
не пуст. -
Когда проверяемое значение не имеет совпадений в списке
IN
и одно из значений являетсяNULL
.
В этих двух случаях предикат IN
вернёт NULL
, в то время как соответствующий предикат EXISTS
вернёт FALSE
.В поисковых условиях или операторе IF
оба результата обозначают “провал” и обрабатываются одинаково.
Однако на тех же данных NOT IN
вернёт NULL
, в то время как EXISTS
вернёт TRUE
, что приведёт к противоположному результату.
Это можно продемонстрировать следующим примером.
Предположим у вас есть такой запрос:
-- Ищем людей, которые не родились в тот же день, что
-- известные жители Нью-Йорка
SELECT P1.name AS NAME
FROM Personnel P1
WHERE P1.birthday NOT IN (SELECT C1.birthday
FROM Celebrities C1
WHERE С1.birthcity = 'New York');
Можно предположить, что аналогичный результат даст запрос с использованием предиката NOT EXISTS
:
-- Ищем людей, которые не родились в тот же день, что
-- известные жители Нью-Йорка
SELECT P1.name AS NAME
FROM Personnel P1
WHERE NOT EXISTS (SELECT *
FROM Celebrities C1
WHERE C1.birthcity = 'New York'
AND C1.birthday = P1.birthday);
Допустим, что в Нью-Йорке всего один известный житель, и его дата рождения неизвестна.При использовании предиката EXISTS
подзапрос внутри него не выдаст результатов, так как при сравнении дат рождения с NULL
результатом будет UNKNOWN
.Это приведёт к тому, что результат предиката NOT EXISTS
будет истинен для каждой строки основного запроса.В то время как результатом предиката NOT IN
будет UNKNOWN
и ни одна строка не будет выведена.
IN
Найти сотрудников с именами “Pete”, “Ann” и “Roger”:
SELECT *
FROM EMPLOYEE
WHERE FIRST_NAME IN ('Pete', 'Ann', 'Roger');
IN
Найти все компьютеры, для которых существуют модели с производителем начинающимися на букву “A”:
SELECT
model, speed, hd
FROM PC
WHERE
model IN (SELECT model
FROM product
WHERE maker STARTING WITH 'A');