Предикат позволяет специфицировать условие вхождения строчного значения в указанное множество значений. Синтаксические правила следующие:
in_predicate ::= row_value_constructor [ NOT ] IN in_predicate_value in_predicate_value ::= table_subquery | (value_expression_comma_list)
Строка, являющаяся первым операндом, и таблица-второй операнд должны быть одинаковой степени. В частности, если второй операнд представляет собой список значений, то первый операнд должен иметь степень 1. Типы данных соответствующих столбцов операндов должны быть совместимы.
Пусть X обозначает строку-первый операнд, а S – множество строк второго операнда. Обозначим через s строку-элемент этого множества. Тогда по определению условие X IN S эквивалентно булевскому выражению OR
(X = s). Другими словами, X IN S принимает значение true в том и только в том случае, когда во множестве S существует хотя бы один элемент s, такой, что значением предиката X = s является true. X IN S принимает значение false в том и только том случае, когда для всех элементов s множества S значением операции сравнения X = s является false. Иначе значением условия X IN S является unknown. Заметим, что для пустого множества S значением X IN S является false.По определению условие X NOT IN S эквивалентно NOT (X IN S).
Пример 19.7. Найти номера отделов, в которых средний размер зарплаты служащих равен максимальному размеру зарплаты служащих какого-либо другого отдела.
SELECT DEPT.DEPT_NO FROM DEPT, EMP WHERE DEPT.DEPT_NO = EMP.DEPT_NO GROUP BY DEPT.DEPT_NO HAVING AVG(EMP.EMP_SAL) IN (SELECT MAX(EMP1.EMP_SAL) FROM EMP, DEPT DEPT1 WHERE EMP.DEPT_NO = DEPT1.DEPT_NO AND DEPT1.DEPT_NO <> DEPT.DEPT_NO GROUP BY DEPT.DEPT_NO);
Этот запрос, помимо прочего, демонстрирует наличие в условии раздела HAVING вложенного подзапроса с корреляцией. Как и раньше, можно избавиться от разделов GROUP BY и HAVING во внешнем запросе (пример 19.7.1):
SELECT DEPT.DEPT_NO FROM DEPT WHERE (SELECT AVG(EMP_SAL) FROM EMP WHERE EMP.DEPT_NO = DEPT.DEPT_NO) IN (SELECT MAX(EMP1.EMP_SAL) FROM EMP, DEPT DEPT1 WHERE EMP.DEPT_NO = DEPT1.DEPT_NO AND DEPT1.DEPT_NO <> DEPT.DEPT_NO GROUP BY DEPT.DEPT_NO);
Но в данном случае мы не можем отказаться от раздела GROUP BY во втором вложенном запросе, поскольку без этого невозможно получить множество значений результатов вызова агрегатной функции.