Предикаты I
Предикаты представляют собой выражения, принимающие истинностное значение. Они могут представлять собой как одно выражение, так и любую комбинацию из неограниченного количества выражений, построенную с помощью булевых операторов AND, OR или NOT. Кроме того, в этих комбинациях может использоваться SQL-оператор IS, а также круглые скобки для конкретизации порядка выполнения операций.
Предикат в языке SQL может принимать одно из трех значений TRUE (истина), FALSE (ложь) или UNKNOWN (неизвестно). Исключение составляют следующие предикаты: IS NULL (отсутствие значения), EXISTS (существование), UNIQUE (уникальность) и MATCH (совпадение), которые не могут принимать значение UNKNOWN.
Правила комбинирования всех трех истинностных значений легче запомнить, обозначив TRUE как 1, FALSE как 0 и UNKNOWN как 1/2 (где-то между истинным и ложным значениями) [2].
AND с двумя истинностными значениями дает минимум этих значений. Например, TRUE AND UNKNOWN будет равно UNKNOWN.
OR с двумя истинностными значениями дает максимум этих значений. Например, FALSE OR UNKNOWN будет равно UNKNOWN.
Отрицание истинностного значения равно 1 минус данное истинностное значение. Например, NOT UNKNOWN будет равно UNKNOWN.
Рекомендуемые упражнения: 5, 33
Логические операторы при отсутствии скобок, как и арифметические операторы, выполняются в соответствии с их старшинством.
Одноместная операция NOT имеет наивысший приоритет. В этом легко убедиться, если выполнить следующие два запроса.
-- модели, не являющиеся ПК
-- второй предикат ничего не меняет, т.к. он добавляет условие,
-- уже учтенное в первом предикате
select maker, model, type
from Product
where not type='PC' or type='Printer';
[[ column ]] |
---|
[[ value ]] |
-- модели производителя A, которые не являются ПК
select maker, model, type
from Product
where not type='PC' and maker='A';
[[ column ]] |
---|
[[ value ]] |
Поменять порядок выполнения логических операторов можно при помощи скобок:
-- модели, не являющиеся ПК или принтером, т.е. модели ноутбуков в нашем случае
select maker, model, type
from Product
where not (type='PC' or type='Printer');
[[ column ]] |
---|
[[ value ]] |
-- модели, которые не являются ПК, выпускаемыми производителем A
select maker, model, type
from Product
where not (type='PC' and maker='A');
[[ column ]] |
---|
[[ value ]] |
Следующий приоритет имеет оператор AND. Сравните результаты следующих запросов.
-- модели ПК, выпускаемые производителем A, и любые модели производителя B
select maker, model, type
from Product
where type='PC' and maker='A' or maker='B';
[[ column ]] |
---|
[[ value ]] |
-- модели ПК, выпускаемые производителем A или производителем B
select maker, model, type
from Product
where type='PC' and (maker='A' or maker='B');
[[ column ]] |
---|
[[ value ]] |
Замечание
Если вы не уверены, что точно помните порядок выполнения логических операторов, ставьте скобки.
Предикат в предложении WHERE выполняет реляционную операцию ограничения, т.е. строки, появляющиеся на выходе предложения FROM ограничиваются теми, для которых предикат дает значение TRUE.
Если cond1 и cond2 являются простыми условиями, то ограничение по предикату
cond1 AND cond2
эквивалентно пересечению ограничений по каждому из предикатов.
Ограничение по предикату
cond1 OR cond2
эквивалентно объединению ограничений по каждому из предикатов, а ограничение по предикату
NOT cond1
эквивалентно взятию разности, когда от исходного отношения вычитается ограничение по предикату cond1.
Обратимся к примерам.
Здесь
cond1: maker = ‘A’ ,
cond2: type = ‘pc’.
cond1 AND cond2
select * from product
where maker = 'A' and type = 'pc';
[[ column ]] |
---|
[[ value ]] |
Пересечение
select * from product
where maker = 'A'
INTERSECT
select * from product
where type = 'pc';
[[ column ]] |
---|
[[ value ]] |
Здесь
cond1: maker = ‘A’ ,
cond2: maker = ‘B’.
cond1 OR cond2
select * from product
where maker = 'A' OR maker = 'B';
[[ column ]] |
---|
[[ value ]] |
Объединение
select * from product
where maker = 'A'
UNION
select * from product
where maker = 'B';
[[ column ]] |
---|
[[ value ]] |
В свою очередь, условия condX могут не быть простыми. Например,
Решение
select * from product
where (maker = 'A' OR maker = 'B') and type = 'pc';
[[ column ]] |
---|
[[ value ]] |
select * from product
where maker = 'A' OR maker = 'B'
INTERSECT
select * from product
where type = 'pc';
[[ column ]] |
---|
[[ value ]] |
select * from product
where (maker = 'A' and type = 'pc')
OR (maker = 'B' and type = 'pc');
[[ column ]] |
---|
[[ value ]] |
select * from product
where maker = 'A' and type = 'pc'
UNION
select * from product
where maker = 'B' and type = 'pc';
[[ column ]] |
---|
[[ value ]] |
Здесь
cond1: type = ‘pc’
NOT cond1
select * from product
where NOT type = 'pc';
[[ column ]] |
---|
[[ value ]] |
Разность
select * from product
EXCEPT
select * from product where type = 'pc';
[[ column ]] |
---|
[[ value ]] |
Несколько слов о производительности
Если на столбцах, по которым выполняется ограничение нет индексов, при выполнении запроса будет выполнено сканирование таблицы. В первых вариантах решений такое сканирование будет выполнено один раз, в то время как в решениях на основе объединения, пересечения и разности запросов таблица сканируется дважды, плюс будет выполнена операция, сравнивающая наборы строк, возвращаемые каждым из запросов (например, Nested Loops). Это делает запрос менее производительным, хотя, возможно, существуют оптимизаторы, способные построить один и тот же план в двух сравниваемых нами случаях.