3.3. Выражения запросов

Хотя на вид (на примерах) выражения запросов SQL/92 очень напоминают соответствующие конструкции SQL/89, на самом деле они гораздо мощнее. Для того, чтобы можно было лучше понять существо выражений запросов SQL/92, мы начнем с рассмотрения вспомогательных конструкций. Заметим, что синтаксические определения часто носят рекурсивный характер, но это "хорошая" рекурсия, потому что в конечном счете любой запрос опирается на именованные базовые или представляемые таблицы.

Итак, сначала введем некоторые начальные понятия, связанные с запросами. Наверное, наиболее важным из таких понятий в SQL/92 является ссылка на таблицу (tablereference), которая может встречаться во всех конструкциях, адресуемых к таблицам. Ссылка на таблицу определяется следующими синтаксическими правилами:

<table reference> ::=  <table name> [ [ AS ] <correlation name>
       [ <left paren> <derived column list> <right paren> ] ]
       |<derived table> [ AS ] <correlation name>
       [ <left paren> <derived column list> <right paren> ]
       |<joined table>
<derived table> ::= <table subquery>
<derived column list> ::= <column name list>
<column name list> ::=
       <column name> [ { <comma> <column name> }... ]

       

Пояснения: Как видно, в отличие от SQL/89, где ссылка на таблицу всегда задается ее именем, в SQL/92 возможны еще два варианта: задать таблицу запросом в традиционной форме или выражением с использованием операторов соединения. Как выглядят эти два варианта, мы увидим в следующих подразделах.

Еще два понятия, более мелких, но необходимых, - конструктор значения-строки и конструктор значения-таблицы. Конструктор значения строки строит из скалярных значений упорядоченный набор, представляющий строку (возможно и использование подзапроса):

<row value constructor> ::=
       <row value constructor element>
       |<left paren> <row value constructor list> <right paren>
       |<row subquery>
<row value constructor list> ::=
       <row value constructor element>
       [ { <comma> <row value constructor element> }... ]
<row value constructor element> ::=
       <value expression>
       |<null specification>
       |<default specification>
<null specification> ::=  NULL
<default specification> ::=  DEFAULT

Заметим, что значение элемента по умолчанию можно использовать только в том случае, когда конструктор значения-строки используется в операторе INSERT (тогда этим значением будет значение по умолчанию соответствующего столбца).

Конструктор значения-таблицы производит таблицу на основе заданного набора конструкторов значений-строк:

<table value constructor> ::=
       VALUES <table value constructor list>
<table value constructor list> ::=
       <row value constructor>
       [ { <comma> <row value constructor> }... ]

Пояснение: Конечно, для того, чтобы корректно построить таблицу, требуется, чтобы строки, производимые всеми конструкторами строк, были одной и той же степени и чтобы типы (или домены) соответствующих столбцов совпадали.

3.3.1. Табличные выражения

Как и в SQL/89, табличное выражение SQL/92 в качестве результата выдает обычную или сгруппированную таблицу:

<table expression> ::=
       <from clause>
       [ <where clause> ]
       [ <group by clause> ]
       [ <having clause> ]

Все отличия от SQL/89 сосредоточены в разделах табличного выражения.

3.3.1.1. Раздел FROM

Формально синтаксис остался таким же, как и в SQL/89:

<from clause> ::=
       FROM <table reference>
       [ { <comma> <table reference> }... ]

Но вспомним, что такое ссылка на таблицу в SQL/92 (см. выше). Реально можно весь запрос сосредоточить в разделе FROM.

3.3.1.2. Раздел WHERE

Снова синтаксис формально не изменился:

<where clause> ::= WHERE <search condition>

Но существенно расширен набор допустимых предикатов (см. следующий раздел).

Разделы GROUPBY и HAVING остались такими же, как в SQL/89, если не считать расширения набора предикатов, которые можно использовать в условии HAVING.

Минимальный осмысленный контекст использования табличных выражений составляет спецификация запроса - один из основных строительных блоков для построения выражения запросов. Синтаксис спецификации запросов следующий:

<query specification> ::=
       SELECT [ <set quantifier> ] <select list> <table expression>
<select list> ::=
       <asterisk>
       |<select sublist> [ { <comma> <select sublist> }... ]
<select sublist> ::=
       <derived column>
       |<qualifier> <period> <asterisk>
<derived column> ::= <value expression> [ <as clause> ]
<as clause> ::= [ AS ] <column name>

Опять же на вид это очень похоже на соответствующую конструкцию SQL/89, но нужно иметь в виду, что, во-первых, в основе спецификации запроса SQL/92 лежит существенно расширенная конструкция табличного выражения, а во-вторых, в спецификации присутствует необязательный раздел AS, позволяющий присвоить имена таблице, которая генерируется при выполнении запроса. Эта возможность кажется на первый взгляд мелочью, но именно она позволяет использовать порождаемые таблицы в разделе FROM и отказаться от использования номеров столбцов порождаемой таблицы в разделе ORDERBY выражения запросов (см. ниже).

3.3.2. Соединенные таблицы

Конструкция соединенной таблицы - это альтернативный способ порождения новой таблицы на основе использования ранее определенных таблиц (базовых, представляемых или порожденных). Для этой конструкции аналоги в SQL/89 отсутствуют. Фактически соединенная таблица вносит алгебраический стиль в формулировки запросов на языке SQL. Формально соединенная таблица определяется следующими синтаксическими правилами:

<joined table> ::=
       <cross join>
       |<qualified join>
       |<left paren> <joined table> <right paren>
<cross join> ::=
       <table reference> CROSS JOIN <table reference>
<qualified join> ::=
       <table reference> [ NATURAL ] [ <join type> ] JOIN
       <table reference> [ <join specification> ]
<join specification> ::=
       <join condition>
       |<named columns join>
<join condition> ::= ON <search condition>
<named columns join> ::=
       USING <left paren> <join column list> <right paren>
<join type> ::=
       INNER
       |<outer join type> [ OUTER ]
       |UNION
<outer join type> ::=
       LEFT
       |RIGHT
       |FULL
<join column list> ::= <column name list>

Поскольку раньше мы не встречались с подобными конструкциями, приведем сравнительно подробные объяснения. Предположим, что соединяются таблицы T1 и T2. Пусть CP обозначает их расширенное Декартово произведения: CP = SELECT * FROMT1, T2.

  1. Если специфицировано квалифицированное соединение (qualifiedjoin), то
  2. Если специфицировано квалифицированное соединение, и не указан тип соединения (jointype), то неявно предполагается внутреннее (INNER) соединение.
  3. Если специфицировано квалифицированное соединение с условием соединения (joincondition), то
  4. Если не указано ни NATURAL, ни спецификация соединения, содержащая только имена столбцов соединения (namedcolumnsjoin), то описатели столбцов результата такие же, как описатели столбцов CP.
  5. Если указано NATURAL или если спецификация запроса содержит только имена столбцов соединения, то
  6. Каждый столбец CR результата соединенной таблицы, который не является столбцом соединения и соответствует столбцу C1 таблицы T1, потенциально может содержать неопределенные значения, если выполняется любое из следующих условий:
  7. Каждый столбец CR результата соединенной таблицы, который не является столбцом соединения и соответствует столбцу C2 таблицы T2, потенциально может содержать неопределенные значения, если выполняется любое из следующих условий:
  8. Каждый столбец CR результата соединенной таблицы, который является столбцом соединения и соответствует столбцам C1 таблицы T1 и C2 таблицы T2, потенциально может содержать неопределенные значения, если выполняется любое из следующих условий:
  9. Соединенная таблица является только читаемой.
  10. Определим T следующим образом:
  11. Пусть P1 - мультимножество строк из T1, для которых в T существует некоторая строка, являющаяся конкатенацией некоторой строки R1 из P1 и некоторой строки R2 из T2. Пусть P2 - мультимножество строк из T2, для которых в T существует некоторая строка, являющаяся конкатенацией некоторой строки R1 из T1 и некоторой строки R2 из P2.
  12. Пусть мультимножество U1 составляют те строки из T1, которые не входят в P1, а U2 - строки, которые не входят в P2.
  13. Пусть D1 и D2 - степени T1 и T2 соответственно. Пусть X1 получается из U1 путем расширения вправо на D2 столбцов, содержащих неопределенные значения, а X2 - из U2 путем расширения влево на D1 столбцов, содержащих неопределенные значения.
  14. Результат соединенной таблицы S получается следующим образом:
  15. Если указаны NATURAL или список имен столбцов соединения, то окончательный результат соединенной таблицы - это мультимножество строк из S, получаемое в результате выполнения следующего запроса: SELECTSLCC, SL1, SL2 FROMS. В противном случае окончательным результатом является S.

3.3.3. Подзапросы

В стандарте SQL/92 специфицированы три вида подзапросов: скалярный, строчный и табличный. Скалярный подзапрос выдает одно значение некоторого типа; строчный подзапрос выдает одну строку; табличный подзапрос выдает таблицу. В основе каждого вида подзапроса лежит табличное выражение. Синтаксически соответствующие конструкции определяются следующими правилами:

<scalar subquery> ::= <subquery>
<row subquery> ::= <subquery>
<table subquery> ::= <subquery>
<subquery> ::= <left paren> <query expression> <right paren>

Пояснения:

  1. Степень скалярного подзапроса должна быть равна 1.
  2. Степень строчного подзапроса должна быть больше 1.
  3. Тип данных скалярного подзапроса совпадает с типом данных соответствующего столбца выражения запросов.
  4. Типы данных столбцов строчного или табличного подзапроса совпадают с типами данных соответствующих столбцов выражения запросов.
  5. Если мощность скалярного или строчного подзапроса больше 1, то возбуждается исключительное условие.

Теперь мы в состоянии привести синтаксические определения и соответствующие пояснения по поводу выражения запросов:

<query expression> ::=
       <non-join query expression>
       |<joined table>
<non-join query expression> ::=
       <non-join query term>
       |<query expression> UNION [ ALL ]
       [ <corresponding spec> ]
       |<query term> <query expression> EXCEPT [ ALL ]
       [ <corresponding spec> ] <query term>
<query term> ::=
       <non-join query term>
       |<joined table>
<non-join query term> ::=
       <non-join query primary>
       |<query term> INTERSECT [ ALL ]
       [ <corresponding spec> ] <query primary>
<query primary> ::=
       <non-join query primary>
       |<joined table>
<non-join query primary> ::=
       <simple table>
       |<left paren> <non-join query expression> <right paren>
<simple table> ::=
       <query specification>
       |<table value constructor>
       |<explicit table>
<explicit table> ::= TABLE <table name>
<corresponding spec> ::=
       CORRESPONDING
       [ BY <left paren> <corresponding column list> <right paren> ]
<corresponding column list> ::= <column name list>

Пояснения:

  1. Если в терме или выражении запросов без соединения присутствует теоретико-множественный оператор, то пусть T1, T2 и TR обозначают соответственно первый операнд, второй операнд и результат терма или выражения, а OP - используемую теоретико-множественную операцию.
  2. Если специфицировано CORRESPONDING, то
  3. Если CORRESPONDING не указано, то T1 и T2 должны быть одинаковой степени.
  4. Если не задан теоретико-множественный оператор, то результатом вычисления выражения запросов является результат вычисления простой или соединенной таблицы.
  5. Если теоретико-множественный оператор задан, то результатом его применения является таблица, содержащая следующие строки:

3.4. Допустимые предикаты и условия поиска

Внешне предикаты, которые можно использовать в условиях поиска SQL/92, очень похожи на предикаты SQL/89. Но, во-первых, ассортимент допустимых предикатов расширен, а во-вторых, возможности задания условий "старых" предикатов стали существенно шире. Поэтому мы перечислим все возможные предикаты с приведением их синтаксиса и кратких пояснений. В конце раздела будут приведены правила формулировки и семантика условий поиска.

Предикат позволяет специфицировать условие, результатом вычисления которого может быть true, false или unknown. В языке SQL/92 допустимы следующие предикаты:

<predicate> ::=
       <comparison predicate>
       |<between predicate>
       |<in predicate>
       |<like predicate>
       |<null predicate>
       |<quantified comparison predicate>
       |<exists predicate>
       |<unique predicate>
       |<match predicate>
       |<overlaps predicate>

3.4.1. Предикат сравнения

В SQL/92 этот предикат предназначен для спецификации сравнения двух строчных значений. Синтаксис предиката следующий:

<comparison predicate> ::=
       <row value constructor> <comp op> <row value constructor>
<comp op> ::=
       <equals operator>
       |<not equals operator>
       |<less than operator>
       |<greater than operator>
       |<less than or equals operator>
       |<greater than or equals operator>

Пояснения:

  1. Строки-операнды должны быть одинаковой степени.
  2. Типы данных соответствующих значений строк-операндов должны быть совместимы.
  3. Пусть X и Y обозначают соответствующие элементы строк-операндов, а XV и YV - их значения
  4. Числа сравниваются в соответствии с алгебраическими значениями.
  5. Сравнение двух текстовых строк производится следующим образом:
  6. Сравнение двух битовых строк X и Y основано на сравнении соответствующих бит. Если Xi и Yi - значения i-тых бит X и Y соответственно и если LX и LY обозначает длину в битах X и Y соответственно, то
  7. Сравнение двух значений типа дата-время производится в соответствии с видом интервала, получающегося при вычитании второго значения из первого. Пусть X и Y - сравниваемые значения, а H - наименее значимое поле даты-времени X и Y. Результат сравнения X <compop> Y определяется как (X - Y) H <compop> INTERVAL (0) H. (Два значения типа дата-время сравнимы только в том случае, если они содержат одинаковый набор полей даты-времени.)
  8. Пусть Rx и Ry обозначают строки-операнды, а RXi и RXi - i-тые элементы Rx и Ry соответственно. Результат сравнения "Rx <compop> Ry" определяется следующим образом:

3.4.2. Предикат between

Как и в SQL/89, предикат позволяет специфицировать условие вхождения в диапазон значений, но в SQL/92 операндами являются строки:

<between predicate> ::=
       <row value constructor> [ NOT ] BETWEEN
       <row value constructor> AND <row value constructor>

Пояснения:

  1. Все три строки-операнды должны иметь одну и ту же степень.
  2. Типы данных соответствующих значений строк-операндов должны быть совместимыми.
  3. Пусть X, Y и Z обозначают первый, второй и третий операнды.
  4. "XNOTBETWEENYANDZ" эквивалентно "NOT (XBETWEENYANDZ)".
  5. "XBETWEENYANDZ" эквивалентно "X>=YANDX<=Z".

3.4.3. Предикат in

Предикат позволяет специфицировать условие вхождения строчного значения в указанное множество значений. Синтаксические правила следующие:

<in predicate> ::=
       <row value constructor>
       [ NOT ] IN <in predicate value>
<in predicate value> ::=
       <table subquery>
       |<left paren> <in value list> <right paren>
<in value list> ::=
       <value expression> { <comma> <value expression> }...

Пояснения:

  1. Пусть IVL обозначает список включаемых значений (<invaluelist>). Тогда (IVL) эквивалентно конструктору табличного значения (VALUESIVL).
  2. Пусть RVC обозначает строку-первый операнд, а IPV - множество значений (<inpredicatevalue>.
  3. Выражение RVCNOTINIPV эквивалентно NOT (RVCINIPV).
  4. Выражение RVCINIPV эквивалентно RVC = ANYIPV.

3.4.4. Предикат like

Формально предикат определяется следующими синтаксическими правилами:

<like predicate> ::=
       <match value> [ NOT ] LIKE <pattern>
       [ ESCAPE <escape character> ]
<match value> ::= <character value expression>
<pattern> ::= <character value expression>
<escape character> ::= <character value expression>

Пояснения: Если не считать того, что в соответствующем условии можно использовать выражения, вырабатывающие значения типа символьных строк, и того, что для используемого набора символов может быть явно задан порядок сортировки, смысл предиката LIKE в SQL/92 не изменился по сравнению с SQL/89.

3.4.5. Предикат null

Как и в SQL/89, предикат null позволяет проверить, не является ли значение неопределенным, но теперь в нем можно использовать операнд-строку:

<null predicate> ::= <row value constructor> IS [ NOT ] NULL

Пояснения:

  1. Пусть R обозначает значение строки-операнда.
  2. Если все значения, входящие в R, являются неопределенными, значение условия "RISNULL" есть true; иначе - false.
  3. Если ни одно из значений R не является неопределенным, то значением условия "RISNOTNULL" является true; иначе - false.

Замечание: для всех R условие "RISNOTNULL" имеет то же значение, что условие "NOTRISNULL" в том и только в том случае, когда степень R равна 1. Полная семантика предиката null приведена в следующей таблице:
УсловиеRISNULLRISNOTNULLNOTRISNULLNOTRISNOTNULL
Степень 1: nulltruefalsefalsetrue
Степень 1: notnullfalsetruetruefalse
Степень > 1: все nulltruefalsefalsetrue
degree > 1: есть nullfalsefalsetruetrue
degree > 1: нет nullfalsetruetruefalse

3.4.6. Предикат сравнения с квантором

Этот предикат позволяет специфицировать квантифицированное сравнение строчного значения и определяется следующими синтаксическими правилами:

<quantified comparison predicate> ::=
       <row value constructor>
       <comp op> <quantifier> <table subquery>
<quantifier> ::= <all> <some>
<all> ::= ALL
<some> ::= SOME ANY

Пояснения:

  1. Степень первого операнда должна быть такой же, как и степень табличного подзапроса.
  2. Типы данных значений строки-операнда должны быть совместимы с типами данных соответствующих столбцов табличного подзапроса.
  3. Сравнение строк производится по тем же правилам, что и для предиката сравнения (п. 3.4.1).
  4. В остальном вычисление условий с кванторами some и all производится так же, как для предиката с квантором в языке SQL/89.

3.4.7. Предикат exists

Этот предикат имеет тот же смысл, что и соответствующий предикат языка SQL/89, но теперь его операндом может быть табличный подзапрос:

<exists predicate> ::= EXISTS <table subquery>

Пояснение: Если мощность табличного подзапроса больше нуля, то значение соответствующего условия есть true; иначе - false.

3.4.8. Предикат unique

Этот предикат позволяет сформулировать условие отсутствия дубликатов в результате запроса:

<unique predicate> ::= UNIQUE <table subquery>

Пояснение: результат вычисления условия UNIQUE <tablesubquery> есть true, если в таблице-результате вычисления табличного подзапроса нет таких двух строк, что значение каждого столбца одной строки не является неопределенным и равным значению соответствующего столбца второй строки; в противном случае значение условия есть false.

3.4.9. Предикат match

Предикат позволяет сформулировать условие соответствия строчного значения результату табличного подзапроса. Синтаксис определяется следующим правилом:

<match predicate> ::=
       <row value constructor>
       MATCH [ UNIQUE ] [ PARTIAL FULL ] <table subquery>

Пояснения:

  1. Степень первого операнда должна совпадать со степенью табличного подзапроса.
  2. Типы данных первого операнда должны быть совместимы с типами соответствующих столбцов табличного подзапроса.
  3. Сравнение пар соответствующих значений производится аналогично тому, как это специфицировалось для предиката сравнения.
  4. Пусть R обозначает строку-первый операнд.
  5. Если не указано ни PARTIAL, ни FULL, то
  6. Если указано PARTIAL, то
  7. Если указано FULL, то

3.4.10. Предикат overlaps

Этот предикат служит для проверки перекрытия во времени двух событий. Условие определяется следующим синтаксисом:

<overlaps predicate> ::=
       <row value constructor 1> OVERLAPS
       <row value constructor 2>
<row value constructor 1> ::= <row value constructor>
<row value constructor 2> ::= <row value constructor>

Пояснения:

  1. Степень каждой из строк-операндов должна быть равна 2.
  2. Тип данных первого столбца каждого из операндов должен быть типом даты-времени, и типы данных первых столбцов должны быть совместимы.
  3. Тип данных второго столбца каждого из операндов должен быть типом даты-времени или интервала.
  4. Пусть D1 и D2 обозначают значения первого столбца первого и второго операндов соответственно.
  5. Если второй столбец первого операнда имеет тип дата-время, то пусть E1 обозначает его значение.
  6. Если второй столбец первого операнда имеет тип INTERVAL, то пусть I1 обозначает его значение, а E1 = D1 + I1.
  7. Если D1 - неопределенное значение или если E1 < D1, то пусть S1 = E1 и T1 = D1. Иначе, пусть S1 = D1 и T1 = E1.
  8. Аналогично определяются S2 и T2 применительно ко второму операнду.
  9. Результат условия совпадает с результатом вычисления следующего выражения:
(S1 > S2 ANDNOT (S1 >= T2 ANDT1 >= T2))
       OR
(S2 > S1 ANDNOT (S2 >= T1 ANDT2 >= T1))
       OR
(S1 = S2 AND (T1 <> T2 ORT1 = T2))

3.4.11. Условие поиска

Условие поиска принимает значения true, false или unknown в зависимости от результата применения булевских операторов к составляющим его простым условиям. Синтаксис и семантика условия поиска в SQL/92 практически такие же, как в SQL/89, но в стандарте SQL/92 более четко специфицирована трехзначная логика, в которой происходит вычисление условия поиска. Синтаксис определяется следующими правилами:

<search condition> ::=
       <boolean term>
       |<search condition> OR <boolean term>
<boolean term> ::=
       <boolean factor>
       |<boolean term> AND <boolean factor>
<boolean factor> ::= [ NOT ] <boolean test>
<boolean test> ::=
       <boolean primary> [ IS [ NOT ] <truth value> ]
<truth value> ::=
       TRUE
       |FALSE
       |UNKNOWN
<boolean primary> ::=
       <predicate>
       | <left paren> <search condition> <right paren>

Пояснения:

  1. Если условие поиска не содержит булевских операторов, то результат его вычисления совпадает с результатом составляющего его простого условия, задаваемого одним из перечисленных выше предикатов.
  2. NOT(true) есть false, NOT(false) есть true и NOT(unknown) есть unknown. Правила применения других булевских операторов задаются следующими таблицами истинности:

Таблица истинности для оператора AND
 truefalseunknown
truetruefalseunknown
falsefalsefalsefalse
unknownunknownfalseunknown

Таблица истинности для оператора OR
 truefalseunknown
truetruetruetrue
falsetruefalseunknown
unknowntrueunknownunknown

Таблица истинности для оператора IS
 truefalseunknown
truetruetruefalse
falsefalsetruefalse
unknownfalsefalseunknown

Назад | Содержание | Вперед