В этой главе рассматриваются элементы, которые являются общими для всех реализаций языка SQL — выражения, которые используются для извлечения и работают на утверждениях о данных, и предикатов, которые проверяют истинность этих утверждений.
В этой главе рассматриваются элементы, которые являются общими для всех реализаций языка SQL — выражения, которые используются для извлечения и работают на утверждениях о данных, и предикатов, которые проверяют истинность этих утверждений.
Выражения SQL представляют формальные методы для вычисления, преобразования и сравнения значений.Выражения SQL могут включать в себя столбцы таблиц, переменные, константы, литералы, различные операторы и предикаты, а так же другие выражения.Полный список допустимых символов (tokens) в выражениях описан ниже.
Идентификаторы столбцов из указанных таблиц, используемые ввычислениях, или сравнениях, или в качестве условия поиска. Столбецтипа массив не может быть элементом выражения, если только он непроверяется на IS [NOT] NULL
.
В выражении может содержаться ссылка на элемент массива, т.е. <array_name>[s]
, где s — индекс элемента в массиве.
Символы +
, -
, *
, /
используемые для вычисления значений.
Оператор ||
(“две вертикальные линии”) используется для соединения символьных строк.
Зарезервированные слова NOT
, AND
и OR
используются прикомбинировании простых условий поиска для создания сложныхутверждений.
Символы =
, <>
, !=
, ~=
, ^=
, <
, <=
, >
, >=
, !<
, ~<
, ^<
, !>
, ~>
и ^>
LIKE
, STARTING WITH
, CONTAINING
, SIMILAR TO
, BETWEEN
, IS [NOT]NULL
, IS [NOT] {TRUE | FALSE | UNKNOWN}
, и IS [NOT] DISTINCT FROM
Предикаты, используемые для проверки существования значений внаборе. Предикат IN может быть использован как с наборами констант,так и со скалярными подзапросами. Предикаты EXISTS, SINGULAR, ALLANY, SOME могут быть использованы только с подзапросами.
Числа, заключённые в апострофы строковые литералы, логическиезначения TRUE
, FALSE
и UNKNOWN
, псевдозначение NULL
.
Выражения, подобные строковым литералам, заключённые вапострофах, которые могут быть интерпретированы как значения даты,времени или даты-времени. Литералами дат могут быть строки изсимволов и чисел, такие как TIMESTAMP '25.12.201615:30:35'
, которые могут быть преобразованы в дату, времяили дату с временем.
Строковый литерал с описанием желаемого значения даты и/иливремени, которое можно привести к типу даты и/или времени. Дляпримера 'NOW'
, 'TODAY'
.
Встроенные контекстные переменные.
Локальные переменные, входные или выходные параметры PSQL модулей(хранимых процедур, триггеров, анонимных блоков PSQL).
В DSQL в качестве параметров запроса могут быть использованытолько позиционные параметры. Позиционные параметры представляютсобой знаки вопроса (?) внутри DSQL оператора. Доступ к такимпараметрам осуществляется по его номеру (позиции в запросеотносительно предыдущего позиционного параметра) поэтому ониназываются позиционными. Обычно компоненты доступа позволяютработать с именованными параметрами, которые они самипреобразовывают в позиционные.
Оператор SELECT заключённый в круглые скобки, который возвращаетодно единственное (скалярное) значение или множество значений (прииспользовании в предикатах существования).
Идентификаторы встроенных или внешних функций в функциональныхвыражениях.
Выражение явного преобразования одного типа данных в другой с использованием CAST
какCAST(<value> AS <datatype>)
.
Выражение CASE
и встроенные функции COALESCE
, NULLIF
.
Пара скобок ( … ) используются для группировки выражений.Операции внутри скобок выполняются перед операциями вне скобок. Прииспользовании вложенных скобок, сначала вычисляются значения самыхвнутренних выражений, а затем вычисления перемещаются наверх поуровням вложенности.
COLLATE
Предложение применяется к типам CHAR
и VARCHAR
, чтобы в указаннойкодировке установить параметры сортировки, используемые присравнении.
NEXT VALUE FOR sequence
Конструкция NEXT VALUE FOR
позволяет получить следующее значениепоследовательности, то же самое делает встроенная функция GEN_ID()
.
AT
Выражение для изменения часового пояса даты и времени.
Литерал или константа — это значение, подставляемое непосредственно в SQL оператор, которое не получено из выражения, параметра, ссылки на столбец или переменной.
Строковый литерал это последовательность символов, заключенных между парой апострофов (“одинарных кавычек”). Максимальная длина строковой константы составляет 65535 байт; максимальная количество символов будет определяться количеством байт, используемых для кодирования каждого символа.
<character string literal> ::= [ <introducer> <character set specification> ] <quote> [ <character representation>... ] <quote> [ { <separator> <quote> [ <character representation>... ] <quote> }... ] <separator> ::= { <comment> | <white space> } <introducer> ::= underscore (U+005F) <quote> ::= apostrophe (U+0027) <char> ::= character representation; apostrophe is escaped by doubling
'Hello world'
Если литерал апострофа требуется в строковой константе, то он может быть “экранирован” другим предшествующим апострофом.
'Mother O''Reilly's home-made hooch'
Другой способ записать данный строковый литерал использовать альтернативные кавычки:
q'{Mother O'Reilly's home-made hooch}'
При необходимости строковый литерал может быть "прерван" пробелом или комментарием.Это может быть использовано для разбиения длинного литерала на несколько строк или предоставления встроенных комментариев.
-- whitespace between literal
select 'ab'
'cd'
from RDB$DATABASE;
-- output: 'abcd'
-- comment and whitespace between literal
select 'ab' /* comment */ 'cd'
from RDB$DATABASE;
-- output: 'abcd'
Note
|
Предполагается, что набор символов строковой константы совпадает с набором символов столбца предназначенного для её сохранения. |
Вместо двойного (экранированного) апострофа вы можете использовать другой символ или пару символов.
Ключевое слово q
или Q
предшествующее строке в кавычках сообщает парсеру, что некоторые левые и правые пары одинаковых символов являются разделителями для встроенного строкового литерала.
<alternate string literal> ::= { q | Q } <quote> <alternate start char> [ { <char> }... ] <alternate end char> <quote>
Note
|
Правила использования
Когда <alternate start char> является одним из символов '(', '{', '[' или '<', то <alternate end char> должен бытьиспользован в паре с соответствующим “партнёром”, а именно ')', '}', ']' или '>'. В других случаях <alternate end char> совпадает с <alternate start char>. Внутри строки, т.е. <char> элементах, одиночные (не экранированные) кавычки могут быть использованы.Каждая кавычка будет частью результирующей строки. |
-- result: abc{def}ghi
SELECT Q'{abc{def}ghi}' FROM rdb$database;
-- result: That's a string
SELECT Q'!That's a string!' FROM rdb$database;
EXECUTE BLOCK
RETURNS (
RDB$TRIGGER_NAME CHAR(64)
)
AS
DECLARE VARIABLE S VARCHAR(8191);
BEGIN
S = 'SELECT RDB$TRIGGER_NAME FROM RDB$TRIGGERS WHERE RDB$RELATION_NAME IN ';
S = S || Q'! ('SALES_ORDER', 'SALES_ORDER_LINE')!';
FOR
EXECUTE STATEMENT :S
INTO :RDB$TRIGGER_NAME
DO
SUSPEND;
END
При необходимости строковому литералу может предшествовать имя набор символов, который начинается с префикса подчеркивания “_”.Это известно как вводный синтаксис (Introducer syntax). Его цель заключается в информировании Firebird о том, как интерпретировать и хранить входящую строку.
-- обратите внимание на префикс '_'
INSERT INTO People
VALUES (_ISO8859_1 'Hans-Jörg Schäfer');
Начиная с Firebird 2.5 строковые константы могут быть записаны в шестнадцатеричной нотации, так называемые “двоичные строки”.Каждая пара шестнадцатеричных цифр определяет один байт в строке.Строки введённые таким образом будут иметь кодировку OCTETS
по умолчанию,но вводный синтаксис (introducer syntax) может быть использован для принудительной интерпретации строки в другом наборе символов.
<binary string literal> ::= {x | X} <quote> [<space>...] [ { <hexit> [<space>...] <hexit> [<space>...] }... ] <quote> [ { <separator> <quote> [ <space>... ] [ { <hexit> [ <space>... ] <hexit> [ <space>... ] }... ] <quote> }... ] <hexit> ::= an even number of <hexdigit> <hexdigit> ::= 0..9 | A..F | a..f
SELECT x'4E657276656E' FROM rdb$database
-- returns 4E657276656E, a 6-byte 'binary' string
SELECT _ascii x'4E657276656E' FROM rdb$database
-- returns 'Nerven' (same string, now interpreted as ASCII text)
SELECT _iso8859_1 x'53E46765' FROM rdb$database
-- returns 'Säge' (4 chars, 4 bytes)
SELECT _utf8 x'53C3A46765' FROM rdb$database
-- returns 'Säge' (4 chars, 5 bytes)
Note
|
Как будут отображена двоичная строка зависит от интерфейса клиента.Например, утилита Шестнадцатеричная нотация позволяет вставить любой байт (включая |
Литерал может содержать пробелы для разделения шестнадцатеричных символов.При необходимости строковый литерал может быть "прерван" пробелом или комментарием.Это может быть использовано для того, чтобы сделать шестнадцатеричную строку более читаемой путем группировки символов,или для разбиения длинного литерала на несколько строк, или для предоставления встроенных комментариев.
-- Group per byte (whitespace inside literal)
select _win1252 x'42 49 4e 41 52 59'
from RDB$DATABASE;
-- output: BINARY
-- whitespace between literal
select _win1252 x'42494e'
'415259'
from RDB$DATABASE;
-- output: BINARY
Числовая константа — это любое правильное число в одной из поддерживаемых нотаций:
В SQL, для чисел в стандартной десятичной записи, десятичная точка всегда представлена символом точки и тысячи не разделены. Включение запятых, пробелов, и т.д. вызовет ошибки.
Экспоненциальная запись, например число 0.0000234 может быть записано как 2.34e-5
.
Шестнадцатеричная запись (см. ниже) чисел поддерживается начиная с Firebird 2.5.
Далее показаны форматы числовых литералов и их типы.Где <d>
- десятичная цифра, <h>
- шестнадцатеричная цифра.
Формат | Тип |
---|---|
|
|
|
|
|
Для обеспечения обратной совместимости некоторые значения из 19 цифр отображаются на |
|
|
Константы целочисленных типов можно указать в шестнадцатеричном формате.Начиная с Firebird 4.0.1 числа состоящие из 17-32 шестнадцатеричных цифр будут интерпретированы как INT128
.
{x|X}<hexdigits> <hexdigits> ::= 1-32 of <hexdigit> <hexdigit> ::= 0..9 | A..F | a..f
Количество шестнадцатеричных цифр | Тип данных |
---|---|
1-8 |
INTEGER |
9-16 |
BIGINT |
17-32 |
INT128 |
SELECT 0x6FAA0D3 FROM rdb$database -- returns 117088467
SELECT 0x4F9 FROM rdb$database -- returns 1273
SELECT 0x6E44F9A8 FROM rdb$database -- returns 1850014120
SELECT 0x9E44F9A8 FROM rdb$database -- returns -1639646808 (an INTEGER)
SELECT 0x09E44F9A8 FROM rdb$database -- returns 2655320488 (a BIGINT)
SELECT 0x28ED678A4C987 FROM rdb$database -- returns 720001751632263
SELECT 0xFFFFFFFFFFFFFFFF FROM rdb$database -- returns -1
Шестнадцатеричные числа в диапазоне 0 .. 7FFF FFFF являются положительными INTEGER
числа со значениями 0 .. 2147483647. Для того чтобы интерпретировать константу как BIGINT
число, необходимо дописать необходимо количества нулей слева. Это изменит тип, но не значение.
Числа в диапазоне 8000 0000 .. FFFF FFFF требуют особого внимания:
При записи восемью шестнадцатеричный числами, такие как 0x9E44F9A8
, интерпретируется как 32-битное целое. Поскольку крайний левый (знаковый) бит установлен, то такие числа будут находиться в отрицательном диапазоне -2147483648 .. -1.
Числа предварённые одним или несколькими нулями, такие как 0x09E44F9A8
, будут интерпретированы как 64-разрядный BIGINT в диапазоне значений 0000 0000 8000 0000 .. 0000 0000 FFFF FFFF. В этом случае знаковый бит не установлен, поэтому они отображаются в положительном диапазоне 2147483648 .. 4294967295 десятичных чисел.
Таким образом, только в этом диапазоне числа, предварённые совершенно незначимым нулём, имеют кардинально разные значения.Это необходимо знать.
Шестнадцатеричные числа в диапазоне 1 0000 0000 .. 7FFF FFFF FFFF FFFF являются положительными BIGINT
числами.
Шестнадцатеричные числа в диапазоне 8000 0000 0000 0000 .. FFFF FFFF FFFF FFFF являются отрицательными BIGINT
числами.
Числа с типом SMALLINT
не могут быть записаны в шестнадцатеричном виде, строго говоря, так как даже 0x1
оценивается как INTEGER
. Тем не менее, если вы записываете положительное целое число в пределах 16-разрядного диапазона от 0x0000 (десятичный ноль) до 0x7FFF
(десятичное 32767), то оно будет преобразовано в SMALLINT
прозрачно.
Вы можете записать отрицательное SMALLINT
число в шестнадцатеричном виде используя 4-байтное шестнадцатеричное число в диапазоне от 0xFFFF8000
(десятичное -32768) до 0xFFFFFFFF
(десятичное -1).
Логический литерал может быть одним из следующих значений: TRUE
, FALSE
или UNKNOWN
.
SQL операторы включают в себя операторы для сравнения, вычисления, оценки и конкатенации значений.
Приоритет определяет порядок, в котором операторы и получаемые с помощью них значения вычисляются в выражении.
Все операторы разбиты на 4 типа.Каждый тип оператора имеет свой приоритет.Чем выше приоритет типа оператора, тем раньше он будет вычислен.Внутри одного типа операторы имеют собственный приоритет, который также определяет порядок их вычисления в выражении.Операторы с одинаковым приоритетом вычисляются слева направо.Для изменения порядка вычислений операции могут быть сгруппированы с помощью круглых скобок.
Тип оператора | Приоритет | Пояснение |
---|---|---|
Конкатенация |
1 |
Строки объединяются до выполнения любых других операций. |
Арифметический |
2 |
Арифметические операции выполняются после конкатенациистрок, но перед выполнением операторов сравнения илогических операций. |
Сравнение |
3 |
Операции сравнения вычисляются после конкатенации строк ивыполнения арифметических операций, но до логическихопераций. |
Логический |
4 |
Логические операторы выполняются после всех других типовоператоров. |
Оператор конкатенации ||
соединяет две символьные строки и создаёт одну строку.Символьные стоки могут быть константами или значениями, полученными из столбцов или других выражений.
SELECT LAST_NAME || ', ' || FIRST_NAME AS FULL_NAME
FROM EMPLOYEE
Оператор | Назначение | Приоритет |
---|---|---|
|
Унарный плюс |
1 |
|
Унарный минус |
1 |
|
Умножение |
2 |
|
Деление |
2 |
|
Сложение |
3 |
|
Вычитание |
3 |
UPDATE T
SET A = 4 + 1/(B-C)*D
Оператор | Назначение | Приоритет |
---|---|---|
|
Проверяет, что выражение в левой части является псевдозначением |
1 |
|
Равно, идентично |
2 |
|
Не равно |
2 |
|
Больше |
2 |
|
Меньше |
2 |
|
Больше или равно |
2 |
|
Меньше или равно |
2 |
|
Не больше |
2 |
|
Не меньше |
2 |
В эту же группу входят предикаты сравнения IS DISTINCT FROM, BETWEEN, IN, LIKE, CONTAINING, SIMILAR TO и другие.
IF (SALARY > 1400) THEN
...
Оператор | Назначение | Приоритет |
---|---|---|
|
Отрицание условия поиска. |
1 |
|
Объединяет два предиката и более, каждый из которыхдолжен быть истинным, чтобы истинным был и весьпредикат. |
2 |
|
Объединяет два предиката и более, из которых должен бытьистинным хотя бы один предикат, чтобы истинным был и весьпредикат. |
3 |
IF (A > B OR (A > C AND A > D) AND NOT (C = D)) THEN
...
AT
DSQL, PSQL.
<expr> AT {TIME ZONE <time zone string> | LOCAL} <time zone string> ::= '<time zone>' <time zone> ::= <time zone region> | [+/-] <hour displacement> [: <minute displacement>]
Преобразует время или временную метку в указанный часовой пояс.Если используется ключевое слово LOCAL
, то преобразование происходит в часовой пояс сессии.
AT
select time '12:00 GMT' at time zone '-03'
from rdb$database;
select current_timestamp at time zone 'America/Sao_Paulo'
from rdb$database;
select timestamp '2018-01-01 12:00 GMT' at local
from rdb$database;
NEXT VALUE FOR
Доступно вDSQL, PSQL.
NEXT VALUE FOR sequence-name
Возвращает следующее значение в последовательности (SEQUENCE
). SEQUENCE
является SQL совместимым термином генератора в InterBase и Firebird.Оператор NEXT VALUE FOR
полностью эквивалентен функции GEN_ID (sequence-name, 1)
и является рекомендуемым синтаксисом.
Note
|
|
NEXT VALUE FOR
NEW.CUST_ID = NEXT VALUE FOR CUSTSEQ;
Условное выражение — это выражение, которое возвращает различные значения в зависимости от истинности некоторого условия или условий.В данном разделе описано лишь одно условное выражение CASE
.Остальные условные выражения являются производными встроенными функциями и описаны в разделе Условные функции.
DSQL, ESQL.
Оператор CASE
возвращает только одно значение из нескольких возможных.Есть два синтаксических варианта:
Простой CASE
, сравнимый с Pascal case
или C switch
;
Поисковый CASE
, который работает как серия операторов “if … else if … else if
”.
CASE <test-expr> WHEN <expr> THEN <result> [WHEN <expr> THEN <result> ...] [ELSE <defaultresult>] END
При использовании этого варианта test-expr сравнивается с первым expr,затем вторым expr и так далее,до тех пор, пока не будет найдено совпадение, и тогда возвращается соответствующий результат.Если совпадений не найдено, то возвращается defaultresult из ветви ELSE
.Если нет совпадений, и ветвь ELSE
отсутствует, то возвращается значение NULL
.
Совпадение эквивалентно оператору “=
”, то естьесли test-expr имеет значение NULL
, то он не соответствует ни одному из expr, даже тем, которые имеют значение NULL
.
Результаты необязательно должны быть литеральными значениями, они также могут быть именами полей, переменными, сложными выражениями или NULL
.
CASE
SELECT
NAME,
AGE,
CASE UPPER(SEX)
WHEN 'M' THEN 'Male'
WHEN 'F' THEN 'Female'
ELSE 'Unknown'
END AS SEXNAME,
RELIGION
FROM PEOPLE
Сокращённый вид простого оператора CASE
используется в функции DECODE.
CASE WHEN <bool_expr> THEN <result> [WHEN <bool_expr> THEN <result> …] [ELSE <defaultresult>] END
Здесь <bool_expr> выражение, которое даёт тройной логический результат: TRUE
, FALSE
или NULL
.Первое выражение, возвращающее TRUE
, определяет результат.Если нет выражений, возвращающих TRUE
, то в качестве результата берётся defaultresult из ветви ELSE
.Если нет выражений, возвращающих TRUE
, и ветвь ELSE
отсутствует, результатом будет NULL
.
Как и в простом операторе CASE
, результаты не обязаны быть литеральными значениями: они могут быть полями или именами переменных, сложными выражениями, или NULL
.
CASE
CANVOTE = CASE
WHEN AGE >= 18 THEN 'Yes'
WHEN AGE < 18 THEN 'No'
ELSE 'Unsure'
END;
NULL
в выраженияхNULL
не является значением — это состояние, указывающее, что значение элемента неизвестно или не существует.Это не ноль, не пустота, не “пустая строка”, и оно не ведёт себя как какое-то из этих значений.
При использовании NULL
в числовых, строковых выражениях или в выражениях, содержащих дату/время, в результате вы всегда получите NULL
.При использовании NULL
в логических (булевых) выражениях результат будет зависеть от типа операции и других вовлечённых значений.При сравнении значения с NULL
результат будет неопределённым (UNKNOWN
).
Important
|
Неопределённый логический результат |
NULL
Выражения в этом списке всегда возвратят NULL
:
1 + 2 + 3 + NULL
'Home ' || 'sweet ' || NULL
MyField = NULL
MyField <> NULL
NULL = NULL
not (NULL)
Если вам трудно понять, почему, вспомните, что NULL
— значит “неизвестно”.
NULL
в логических выраженияхМы уже рассмотрели, что not (NULL)
даёт в результате NULL
.Для операторов AND
и OR
взаимодействие несколько сложнее:
NULL or false → NULL NULL or true → true NULL or NULL → NULL NULL and false → false NULL and true → NULL NULL and NULL → NULL
NULL
в логических выражениях(1 = NULL) or (1 <> 1) -- returns NULL
(1 = NULL) or FALSE -- returns NULL
(1 = NULL) or (1 = 1) -- returns TRUE
(1 = NULL) or TRUE -- returns TRUE
(1 = NULL) or (1 = NULL) -- returns NULL
(1 = NULL) or UNKNOWN -- returns NULL
(1 = NULL) and (1 <> 1) -- returns FALSE
(1 = NULL) and FALSE -- returns FALSE
(1 = NULL) and (1 = 1) -- returns NULL
(1 = NULL) and TRUE -- returns NULL
(1 = NULL) and (1 = NULL) -- returns NULL
(1 = NULL) and UNKNOWN -- returns NULL
Подзапрос — это специальный вид выражения, которое фактически является запросом, встроенным в другой запрос.Подзапросы пишутся как обычные SELECT
запросы, но должны быть заключены в круглые скобки.Выражения подзапроса используется следующими способами:
Для задания выходного столбца в списке выбора SELECT
;
Для получения значений или условий для предикатов поиска (предложения WHERE
, HAVING
);
Для создания набора данных, из которого включающий запрос может выбирать, как будто это обычная таблица или представление.Подобные подзапросы появляются в предложении FROM
(производные таблицы) или в общем табличном выражении (CTE).
Подзапрос может быть коррелированным (соотнесённым). Запрос называется коррелированным, когда подзапрос и основной запрос взаимозависимы.Это означает, что для обработки каждой записи подзапроса, должна быть получена также запись из основного запроса, т.е.подзапрос всецело зависит от основного запроса.
SELECT *
FROM Customers C
WHERE EXISTS
(SELECT *
FROM Orders O
WHERE C.cnum = O.cnum
AND O.adate = DATE '10.03.1990');
При использовании подзапросов для получения значений выходного столбца в списке выбора SELECT
, подзапрос должен возвращать скалярный результат.
Подзапросы, используемые в предикатах поиска, кроме предикатов существования и количественных предикатов, должны возвращать скалярный результат, то есть не более чем один столбец из одной отобранной строки или одно агрегированное значение, в противном случае, произойдёт ошибка времени выполнения (“Multiple rows in a singleton select…”).
Note
|
Несмотря на то, что Firebird сообщает о подлинной ошибке, сообщение может немного вводить в заблуждение.“singleton SELECT” — это запрос, который не должен возвращать более одной строки.Однако “singleton” и “scalar” не являются синонимами: не все одноэлементные SELECTS должны быть скалярными; а выборка по одному столбцу может возвращать несколько строк для предикатов существования и количественных предикатов. |
SELECT
e.first_name,
e.last_name,
(SELECT
sh.new_salary
FROM
salary_history sh
WHERE
sh.emp_no = e.emp_no
ORDER BY sh.change_date DESC ROWS 1) AS last_salary
FROM
employee e
WHERE
для получения значения максимальной зарплаты сотрудника и фильтрации по немуSELECT
e.first_name,
e.last_name,
e.salary
FROM
employee e
WHERE
e.salary = (SELECT
MAX(ie.salary)
FROM
employee ie)
Предикат — это простое выражение, утверждающее некоторый факт, назовем его P
.Если P
разрешается как TRUE, он успешен.Если он принимает значение FALSE или NULL (UNKNOWN), он терпит неудачу.Однако здесь кроется ловушка: предположим, что предикат P
возвращает FALSE.В этом случае NOT (P)
вернет TRUE.С другой стороны, если P
возвращает NULL (неизвестно), то NOT (P)
также возвращает NULL.
В SQL предикаты проверяют в ограничении CHECK
, предложении WHERE
, выражении CASE
, условии соединения во фразе ON для предложений JOIN, а также в предложении HAVING
.В PSQL операторы управления потоком выполнения проверяют предикаты в предложениях IF
, WHILE
и WHEN
. Поскольку начиная с Firebird 3.0 введена поддержка логического типа, то предикат может встречаться в любом правильном выражении.
Проверяемые условия не всегда являются простыми предикатами.Они могут быть группой предикатов, каждый из которых при вычислении делает вклад в вычислении общей истинности.Такие сложные условия называются утверждениями.Утверждения могут состоять из одного или нескольких предикатов, связанных логическими операторами AND
, OR
и NOT
. Для группировки предикатов и управления порядком вычислений можно использовать скобки.
Каждый из предикатов может содержать вложенные предикаты.Результат вычисления истинности утверждения получается в результате вычисления всех предикатов по направлению от внутренних к внешним.Каждый “уровень” вычисляется в порядке приоритета до тех пор, пока не будет получено значение истинности окончательного утверждения.
Предикат сравнения представляет собой два выражения, соединяемых оператором сравнения.Имеется шесть традиционных операторов сравнения:
=, >, <, >=, <=, <>
(Полный список операторов сравнения см. Операторы сравнения).
Если в одной из частей (левой или правой) предиката сравнения встречается NULL, то значение предиката будет неопределённым (UNKNOWN).
Получить информацию о компьютерах, имеющих частоту процессора не менее 500 МГц и цену ниже $800
SELECT *
FROM Pc
WHERE speed >= 500 AND price < 800;
Получить информацию обо всех принтерах, которые являются матричными и стоят меньше $300
SELECT *
FROM Printer
WHERE type = 'matrix' AND price < 300;
Следующий запрос не вернёт ни одной записи, поскольку сравнение происходит с псевдо-значением NULL
, даже если существуют принтеры с неуказанным типом.
SELECT *
FROM Printer
WHERE type = NULL AND price < 300;
Note
|
Замечание о сравнении строк
При сравнении на равенство полей типов |
Другие предикаты сравнения состоят из ключевых слов.
BETWEEN
DSQL, PSQL, ESQL.
<value> [NOT] BETWEEN <value_1> AND <value_2>
Предикат BETWEEN
проверяет, попадает (или не попадает при использовании NOT) ли значение во включающий диапазон значений.
Операнды для предиката BETWEEN
— это два аргумента совместимых типов.В отличие от некоторых других СУБД в Firebird предикат BETWEEN
не является симметричным.Меньшее значение должно быть первым аргументом, иначе предикат BETWEEN
всегда будет ложным.Поиск является включающим.Таким образом, предикат BETWEEN
можно переписать следующим образом:
<value> >= <value_1> AND <value> <= <value_2>
При использовании предиката BETWEEN
в поисковых условиях DML запросов, оптимизатор Firebird может использовать индекс по искомому столбцу, если таковой доступен.
BETWEEN
SELECT *
FROM EMPLOYEE
WHERE HIRE_DATE BETWEEN date '01.01.1992' AND CURRENT_DATE
LIKE
DSQL, PSQL, ESQL.
<match value> [NOT] LIKE <pattern> [ESCAPE <escape character>] <match value> ::= выражение символьного типа <pattern> ::= шаблон поиска <escape character> ::= символ экранирования
Предикат LIKE
сравнивает выражение символьного типа с шаблоном, определённым во втором выражении.Чувствительность к регистру или диакритическим знакам при сравнении определяется используемым параметром сортировки (COLLATION
).
При использовании оператора LIKE
во внимание принимаются все символы строки-шаблона.Это касается так же начальных и конечных пробелов.Если операция сравнения в запросе должна вернуть все строки, содержащие строки LIKE 'абв ' (с символом пробела на конце), то строка, содержащая 'абв' (без пробела), не будет возвращена.
В шаблоне, разрешается использование двух трафаретных символов:
символ процента (%
) заменяет последовательность любых символов (число символов в последовательности может быть от 0 и более) в проверяемом значении;
символ подчёркивания (_
), который можно применять вместо любого единичного символа в проверяемом значении.
Если проверяемое значение соответствует образцу с учётом трафаретных символов, то предикат истинен.
ESCAPE
Если искомая строка содержит трафаретный символ, то следует задать управляющий символ в предложении ESCAPE
.Этот управляющий символ должен использоваться в образце перед трафаретным символом, сообщая о том, что последний следует трактовать как обычный символ.
LIKE
LIKE
Поиск номеров отделов, названия которых начинаются со слова “Software”
SELECT DEPT_NO
FROM DEPT
WHERE DEPT_NAME LIKE 'Software%';
В данном запросе может быть использован индекс, если он построен на поле DEPT_NAME.
Note
|
Оптимизация
LIKE В общем случае предикат |
Поиск сотрудников, имена которых состоят из 5 букв, начинающихся с букв “Sm” и заканчивающихся на “th”.В данном случае предикат будет истинен для имен “Smith” и “Smyth”.
SELECT
first_name
FROM
employee
WHERE first_name LIKE 'Sm_th'
LIKE
Поиск всех заказчиков, в адресе которых содержится строка “Ростов”.
SELECT *
FROM CUSTOMER
WHERE ADDRESS LIKE '%Ростов%'
Tip
|
Если вам необходимо выполнить поиск внутри строки, то вместо предиката |
ESCAPE
с предикатом `LIKE
Поиск таблиц, содержащих в имени знак подчёркивания.В данном случае в качестве управляющего символа задан символ “#”.
SELECT
RDB$RELATION_NAME
FROM RDB$RELATIONS
WHERE RDB$RELATION_NAME LIKE '%#_%' ESCAPE '#'
STARTING WITH
DSQL, PSQL, ESQL.
<value> [NOT] STARTING WITH <start-value>
Предикат STARTING WITH
ищет строку, которая начинается с символов в его аргументе start-value.Чувствительность к регистру и ударению в STARTING WITH
зависит от сортировки (COLLATION
) первого аргумента value.
При использовании предиката STARTING WITH
в поисковых условиях DML запросов, оптимизатор Firebird может использовать индекс по искомому столбцу, если он определён.
STARTING WITH
Поиск сотрудников, фамилия которых начинается с “Jo”.
SELECT LAST_NAME, FIRST_NAME
FROM EMPLOYEE
WHERE LAST_NAME STARTING WITH 'Jo'
LIKE.
CONTAINING
DSQL, PSQL, ESQL.
<value> [NOT] CONTAINING <substring>
Оператор CONTAINING
ищет строку или тип, подобный строке, отыскивая последовательность символов, которая соответствует его аргументу.Он может быть использован для алфавитно-цифрового (подобного строковому) поиска в числах и датах.Поиск CONTAINING не чувствителен к регистру.Тем не менее, если используется сортировка чувствительная к акцентам, то поиск будет чувствителен к акцентам.
При использовании оператора CONTAINING
во внимание принимаются все символы строки.Это касается так же начальных и конечных пробелов.Если операция сравнения в запросе должна вернуть все строки, содержащие строки CONTAINING 'абв '
(с символом пробела на конце), то строка, содержащая 'абв'
(без пробела), не будет возвращена.
При использовании предиката CONTAINING
в поисковых условиях DML запросов, оптимизатор Firebird не может использовать индекс по искомому столбцу.
CONTAINING
Поиск проектов в именах, которых присутствует подстрока “Map”:
SELECT *
FROM PROJECT
WHERE PROJ_NAME CONTAINING 'map';
В данном случае будет возвращены две строки с именами “AutoMap” и “MapBrowser port”.
CONTAINING
Поиск записей об изменении зарплат с датой содержащей число 84 (в данном случае изменения, которые произошли в 1984 году):
SELECT *
FROM SALARY_HISTORY
WHERE CHANGE_DATE CONTAINING 84;
LIKE.
SIMILAR TO
DSQL, PSQL.
string-expression [NOT] SIMILAR TO <pattern> [ESCAPE <escape-char>] <pattern> ::= регулярное выражение SQL <escape-char> ::= символ экранирования
Оператор SIMILAR TO
проверяет соответствие строки с шаблоном регулярного выражения SQL.В отличие от некоторых других языков для успешного выполнения шаблон должен соответствовать всей строке — соответствие подстроки недостаточно.Если один из операндов имеет значение NULL
, то и результат будет NULL
.В противном случае результат является TRUE
или FALSE
.
Следующий синтаксис определяет формат регулярного выражения SQL.Это полное и корректное его определение.Он является весьма формальным и довольно длинным и, вероятно, озадачивает тех, кто не имеет опыта работы с регулярными выражениями.Не стесняйтесь пропустить его и начать читать следующий раздел, Создание регулярных выражений, использующий подход от простого к сложному.
<regular expression> ::= <regular term> ['|' <regular term> ...] <regular term> ::= <regular factor> ... <regular factor> ::= <regular primary> [<quantifier>] <quantifier> ::= ? | * | + | '{' <m> [,[<n>]] '}' <m>, <n> ::= целые положительные числа, если присутвуют оба числа, то <m> <= <n> <regular primary> ::= <character> | <character class> | % | (<regular expression>) <character> ::= <escaped character> | <non-escaped character> <escaped character> ::= <escape-char> <special character> | <escape-char> <escape-char> <special character> ::= любой из символов []()|^-+*%_?{} <non-escaped character> ::= любой символ за исключением <special character> и не эквивалентный <escape-char> (если задан) <character class> ::= '_' | '[' <member> ... ']' | '[^' <non-member> ... ']' | '[' <member> ... '^' <non-member> ... ']' <member>, <non-member> ::= <character> | <range> | <predefined class> <range> ::= <character>-<character> <predefined class> ::= '[:' <predefined class name> ':]' <predefined class name> ::= ALPHA | UPPER | LOWER | DIGIT | ALNUM | SPACE | WHITESPACE
В этом разделе представлены элементы и правила построения регулярных выражений SQL.
В регулярных выражениях большинство символов представляет сами себя, за исключением специальных символов (special character):
[ ] ( ) | ^ - + * % _ ? { }
... и управляющих символов (escaped character), если они заданы.
Регулярному выражению, не содержащему специальных или управляющих символов, соответствует только полностью идентичные строки (в зависимости от используемой сортировки). То есть это функционирует точно так же, как оператор “=
”:
'Apple' SIMILAR TO 'Apple' -- TRUE
'Apples' SIMILAR TO 'Apple' -- FALSE
'Apple' SIMILAR TO 'Apples' -- FALSE
'APPLE' SIMILAR TO 'Apple' -- в зависимости от сортировки
Известным SQL шаблонам ‘_
’ и ‘%
’ соответствует любой единственный символ и строка любой длины, соответственно:
'Birne' SIMILAR TO 'B_rne' -- TRUE
'Birne' SIMILAR TO 'B_ne' -- FALSE
'Birne' SIMILAR TO 'B%ne' -- TRUE
'Birne' SIMILAR TO 'Bir%ne%' -- TRUE
'Birne' SIMILAR TO 'Birr%ne' -- FALSE
Обратите внимание, что шаблон ‘%
’ также соответствует пустой строке.
Набор символов, заключённый в квадратные скобки определяют класс символов.Символ в строке соответствует классу в шаблоне, если символ является элементом класса:
'Citroen' SIMILAR TO 'Cit[arju]oen' -- TRUE
'Citroen' SIMILAR TO 'Ci[tr]oen' -- FALSE
'Citroen' SIMILAR TO 'Ci[tr][tr]oen' -- TRUE
Как видно из второй строки классу только соответствует единственный символ, а не их последовательность.
Два символа, соединённые дефисом, в определении класса определяют диапазон.Диапазон для активного сопоставления включает в себя эти два конечных символа и все символы, находящиеся между ними.Диапазоны могут быть помещены в любом месте в определении класса без специальных разделителей, чтобы сохранить в классе и другие символы.
'Datte' SIMILAR TO 'Dat[q-u]e' -- TRUE
'Datte' SIMILAR TO 'Dat[abq-uy]e' -- TRUE
'Datte' SIMILAR TO 'Dat[bcg-km-pwz]e' -- FALSE
Следующие предопределенные классы символов также могут использоваться в определении класса:
[:ALPHA:]
Латинские буквы a…z и A…Z.Этот класс также включает символы с диакритическими знаками при нечувствительных к акцентам сортировках.
[:DIGIT:]
Десятичные цифры 0…9.
[:ALNUM:]
Объединение [:ALPHA:] и [:DIGIT:].
[:UPPER:]
Прописные (в верхнем регистре) латинские буквы A…Z.Также включает в себя символы в нижнем регистре при нечувствительных к регистру сортировках и символы с диакритическими знаками при нечувствительных к акцентам сортировках.
[:LOWER:]
Строчные (в нижнем регистре) латинские буквы a…z.Также включает в себя символы в верхнем регистре при нечувствительных к регистру сортировках и символы с диакритическими знаками при нечувствительных к акцентам сортировках.
[:SPACE:]
Символ пробела (ASCII 32).
[:WHITESPACE:]
Горизонтальная табуляция (ASCII 9), перевод строки (ASCII 10), вертикальная табуляция (ASCII 11), разрыв страницы (ASCII 12), возврат каретки (ASCII 13) и пробел (ASCII 32).
Включение в оператор SIMILAR TO
предопределённого класса имеет тот же эффект, как и включение всех его элементов.Использование предопределённых классов допускается только в пределах определения класса.Если вам нужно сопоставление только с предопределённым классом и ничего больше, то поместите дополнительную пару скобок вокруг него.
'Erdbeere' SIMILAR TO 'Erd[[:ALNUM:]]eere' -- TRUE
'Erdbeere' SIMILAR TO 'Erd[[:DIGIT:]]eere' -- FALSE
'Erdbeere' SIMILAR TO 'Erd[a[:SPACE:]b]eere' -- TRUE
'Erdbeere' SIMILAR TO '[[:ALPHA:]]' -- FALSE
'E' SIMILAR TO '[[:ALPHA:]]' -- TRUE
Если определение класса запускается со знаком вставки (^), то все, что следует за ним, исключается из класса.Все остальные символы проверяются.
'Framboise' SIMILAR TO 'Fra[^ck-p]boise' -- FALSE
'Framboise' SIMILAR TO 'Fr[^a][^a]boise' -- FALSE
'Framboise' SIMILAR TO 'Fra[^[:DIGIT:]]boise' -- TRUE
Если знак вставки (^) находится не в начале последовательности, то класс включает в себя все символы до него и исключает символы после него.
'Grapefruit' SIMILAR TO 'Grap[a-m^f-i]fruit' -- TRUE
'Grapefruit' SIMILAR TO 'Grap[abc^xyz]fruit' -- FALSE
'Grapefruit' SIMILAR TO 'Grap[abc^de]fruit' -- FALSE
'Grapefruit' SIMILAR TO 'Grap[abe^de]fruit' -- FALSE
'3' SIMILAR TO '[[:DIGIT:]^4-8]' -- TRUE
'6' SIMILAR TO '[[:DIGIT:]^4-8]' -- FALSE
Наконец, уже упомянутый подстановочный знак ‘_
’ является собственным классом символов, соответствуя любому единственному символу.
Вопросительный знак (‘?
’) сразу после символа или класса указывает на то, что для соответствия предыдущий элемент должен встретиться 0 или 1 раз:
'Hallon' SIMILAR TO 'Hal?on' -- FALSE
'Hallon' SIMILAR TO 'Hal?lon' -- TRUE
'Hallon' SIMILAR TO 'Halll?on' -- TRUE
'Hallon' SIMILAR TO 'Hallll?on' -- FALSE
'Hallon' SIMILAR TO 'Halx?lon' -- TRUE
'Hallon' SIMILAR TO 'H[a-c]?llon[x-z]?' -- TRUE
Звёздочка (‘*
’) сразу после символа или класса указывает на то, что для соответствия предыдущий элемент должен встретиться 0 или более раз:
'Icaque' SIMILAR TO 'Ica*que' -- TRUE
'Icaque' SIMILAR TO 'Icar*que' -- TRUE
'Icaque' SIMILAR TO 'I[a-c]*que' -- TRUE
'Icaque' SIMILAR TO '_*' -- TRUE
'Icaque' SIMILAR TO '[[:ALPHA:]]*' -- TRUE
'Icaque' SIMILAR TO 'Ica[xyz]*e' -- FALSE
Знак плюс (‘+
’) сразу после символа или класса указывает на то, что для соответствия предыдущий элемент должен встретиться 1 или более раз:
'Jujube' SIMILAR TO 'Ju_+' -- TRUE
'Jujube' SIMILAR TO 'Ju+jube' -- TRUE
'Jujube' SIMILAR TO 'Jujuber+' -- FALSE
'Jujube' SIMILAR TO 'J[jux]+be' -- TRUE
'Jujube' SIMILAR TO 'J[[:DIGIT:]]+ujube' -- FALSE
Если символ или класс сопровождаются числом, заключённым в фигурные скобки (‘{
’ и ‘}
’), то для соответствия необходимо повторение элемента точно это число раз:
'Kiwi' SIMILAR TO 'Ki{2}wi' -- FALSE
'Kiwi' SIMILAR TO 'K[ipw]{2}i' -- TRUE
'Kiwi' SIMILAR TO 'K[ipw]{2}' -- FALSE
'Kiwi' SIMILAR TO 'K[ipw]{3}' -- TRUE
Если число сопровождается запятой (‘,
’), то для соответствия необходимо повторение элемента как минимум это число раз:
'Limone' SIMILAR TO 'Li{2,}mone' -- FALSE
'Limone' SIMILAR TO 'Li{1,}mone' -- TRUE
'Limone' SIMILAR TOto 'Li[nezom]{2,}' -- TRUE
Если фигурные скобки содержат два числа (m и n), разделённые запятой, и второе число больше первого, то для соответствия элемент должен быть повторен, как минимум, m раз и не больше n раз:
'Mandarijn' SIMILAR TO 'M[a-p]{2,5}rijn' -- TRUE
'Mandarijn' SIMILAR TO 'M[a-p]{2,3}rijn' -- FALSE
'Mandarijn' SIMILAR TO 'M[a-p]{2,3}arijn' -- TRUE
Кванторы ‘?
’, ‘*
’ и ‘+
’ являются сокращением для {0,1}
, {0,}
и {1,}
, соответственно.
В условиях регулярных выражений можно использовать оператор ИЛИ ‘|
’. Соответствие произошло, если строка параметра соответствует, по крайней мере, одному из условий:
'Nektarin' SIMILAR TO 'Nek|tarin' -- FALSE
'Nektarin' SIMILAR TO 'Nektarin|Persika' -- TRUE
'Nektarin' SIMILAR TO 'M_+|N_+|P_+' -- TRUE
Одна или более частей регулярного выражения могут быть сгруппированы в подвыражения (также называемые подмасками). Для этого их нужно заключить в круглые скобки (‘(
’ и ‘)
’):
'Orange' SIMILAR TO 'O(ra|ri|ro)nge' -- TRUE
'Orange' SIMILAR TO 'O(r[a-e])+nge' -- TRUE
'Orange' SIMILAR TO 'O(ra){2,4}nge' -- FALSE
'Orange' SIMILAR TO 'O(r(an|in)g|rong)?e' -- TRUE
Для исключения из процесса сопоставления специальных символов (которые часто встречаются в регулярных выражениях) их надо экранировать.Специальных символов экранирования по умолчанию нет — их при необходимости определяет пользователь:
'Peer (Poire)' SIMILAR TO 'P[^ ]+ \(P[^ ]+\)' ESCAPE '\' -- TRUE
'Pera [Pear]' SIMILAR TO 'P[^ ]+ #[P[^ ]+#]' ESCAPE '#' -- TRUE
'Paron-Appledryck' SIMILAR TO 'P%$-A%' ESCAPE '$' -- TRUE
'Parondryck' SIMILAR TO 'P%--A%' ESCAPE '-' -- FALSE
IS DISTINCT FROM
DSQL, PSQL.
<operand1> IS [NOT] DISTINCT FROM <operand2>
Два операнда считают DISTINCT (различными), если они имеют различные значения, или если одно из них — NULL
, а другое нет.Они считаются NOT DISTINCT (равными), если имеют одинаковые значения или оба имеют значение NULL
.
IS [NOT] DISTINCT FROM
всегда возвращает TRUE
или FALSE
и никогда UNKNOWN
(NULL) (неизвестное значение). Операторы ‘=
’ и ‘<>
’, наоборот, вернут UNKNOWN
(NULL), если один или оба операнда имеют значение NULL.
Характеристики операнда |
Результаты различных операторов |
|||
---|---|---|---|---|
|
|
|
|
|
Одинаковые значения |
|
|
|
|
Различные значения |
|
|
|
|
Оба |
|
|
|
|
Одно |
|
|
|
|
IS [NOT] DISTINCT FROM
SELECT ID, NAME, TEACHER
FROM COURSES
WHERE START_DAY IS NOT DISTINCT FROM END_DAY
IF (NEW.JOB IS DISTINCT FROM OLD.JOB) THEN
POST_EVENT 'JOB_CHANGED';
IS [NOT]
DSQL, PSQL.
<value> IS [NOT] {TRUE | FALSE | UNKNOWN}
Оператор IS
проверяет, что выражение в левой части соответствует логическому значению в правой части.Выражение в левой части должно быть логического типа, иначе будет выдана ошибка.
Для логического типа данных предикат IS [NOT] UNKNOWN
эквивалентен IS [NOT] NULL
.
Note
|
Замечание:
В правой части предиката могут быть использованы только литералы |
-- Проверка FALSE значения
SELECT * FROM TBOOL WHERE BVAL IS FALSE
ID BVAL ============ ======= 2 <false>
-- Проверка UNKNOWN значения
SELECT * FROM TBOOL WHERE BVAL IS UNKNOWN
ID BVAL ============ ======= 3 <null>
IS [NOT] NULL
DSQL, PSQL.
<value> IS [NOT] NULL
Поскольку NULL
не является значением, эти операторы не являются операторами сравнения.Оператор IS [NOT] NULL
проверяет, что выражение слева имеет значение (IS NOT NULL) или не имеет значения (IS NULL)
IS [NOT] NULL
Поиск записей о продажах, для которых не установлена дата отгрузки:
SELECT *
FROM SALES
WHERE SHIP_DATE IS NULL;
В эту группу предикатов включены предикаты, которые используют подзапросы и передают значения для всех видов утверждений в условиях поиска.Предикаты существования называются так потому, что они различными способами проверяют существование или отсутствие результатов подзапросов.
EXISTS
DSQL, PSQL, ESQL.
[NOT] EXISTS (<select_stmt>)
Предикат EXISTS
использует подзапрос в качестве аргумента.Если результат подзапроса будет содержать хотя бы одну запись, то предикат оценивается как истинный (TRUE), в противном случае предикат оценивается как ложный (FALSE).
Результат подзапроса может содержать несколько столбцов, поскольку значения не проверяются, а просто фиксируется факт наличия строк результата.Данный предикат может принимать только два значения: истина (TRUE) и ложь (FALSE).
Предикат NOT EXISTS
возвращает FALSE
, если результат подзапроса будет содержать хотя бы одну запись, в противном случае предикат вернёт TRUE
.
EXISTS
Найти тех сотрудников, у которых есть проекты.
SELECT *
FROM employee
WHERE EXISTS (SELECT *
FROM
employee_project ep
WHERE
ep.emp_no = employee.emp_no)
NOT EXISTS
Найти тех сотрудников, у которых нет проектов.
SELECT *
FROM employee
WHERE NOT EXISTS (SELECT *
FROM
employee_project ep
WHERE
ep.emp_no = employee.emp_no)
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');
SINGULAR
DSQL, PSQL, ESQL.
[NOT] SINGULAR (<select_stmt>)
Предикат SINGULAR
использует подзапрос в качестве аргумента и оценивает его как истинный, если подзапрос возвращает одну и только одну строку результата, в противном случае предикат оценивается как ложный.Результат подзапроса может содержать несколько столбцов, поскольку значения не проверяются.Данный предикат может принимать только два значения: истина (TRUE) и ложь (FALSE).
SINGULAR
Найти тех сотрудников, у которых есть только один проект.
SELECT *
FROM employee
WHERE SINGULAR (SELECT *
FROM
employee_project ep
WHERE
ep.emp_no = employee.emp_no)
Квантором называется логический оператор, задающий количество объектов, для которых данное утверждение истинно.Это логическое количество, а не числовое; оно связывает утверждение с полным множеством возможных объектов.Такие предикаты основаны на формальных логических квантификаторах общности и существования, которые распознаются формальной логикой.
В выражениях подзапросов количественные предикаты позволяют сравнивать отдельные значения с результатами подзапросов; их общая форма:
<value expression> <comparison operator> <quantifier> <subquery>
ALL
DSQL, PSQL.
<value> <op> ALL (<select_stmt>)
При использовании квантора ALL
, предикат является истинным, если каждое значение выбранное подзапросом удовлетворяет условию в предикате внешнего запроса.Если подзапрос не возвращает ни одной строки, то предикат автоматически считается верным.
Вывести только тех заказчиков, чьи оценки выше, чем у каждого заказчика в Париже.
SELECT *
FROM Customers
WHERE rating > ALL
(SELECT rating
FROM Customers
WHERE city = 'Paris')
Important
|
Если подзапрос возвращает пустое множество, то предикат будет истинен для каждого левостороннего значения, независимо от оператора.Это может показаться странным и противоречивым, потому что в этом случае каждое левостороннее значение рассматривается как одновременно больше, меньше, равное и неравное любому значению из правого потока. Тем не менее это нормально согласуется с формальной логикой: если множество пусто, то предикат верен 0 раз, т.е.для каждой строки в множестве. |
ANY
и SOME
DSQL, PSQL.
<value> <op> {ANY | SOME} (<select_stmt>)
Эти два квантора идентичны по поведению.Очевидно, оба представлены в стандарте SQL для взаимозаменяемого использования с целью улучшения читаемости операторов.При использовании квантора ANY
или SOME
, предикат является истинным, если любое из значений выбранное подзапросом удовлетворяет условию в предикате внешнего запроса.Если подзапрос не возвращает ни одной строки, то предикат автоматически считается ложным.
Вывести только тех заказчиков, чьи оценки выше, чем у какого-либо заказчика в Риме.
SELECT *
FROM Customers
WHERE rating > ANY
(SELECT rating
FROM Customers
WHERE city = 'Rome')