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 и ни одна строка не будет выведена.
Example 1. Предикат IN
Найти сотрудников с именами “Pete”, “Ann” и “Roger”:
SELECT *
FROM EMPLOYEE
WHERE FIRST_NAME IN ('Pete', 'Ann', 'Roger');
Example 2. Поисковый предикат IN
Найти все компьютеры, для которых существуют модели с производителем начинающимися на букву “A”:
SELECT
model, speed, hd
FROM PC
WHERE
model IN (SELECT model
FROM product
WHERE maker STARTING WITH 'A');