Введение в стандарты языка баз данных SQL

         

Агрегатные функции и результаты запросов


Агрегатные функции (в стандарте SQL/89 они называются функциями над множествами) определяются в SQL/89 следующими синтаксическими правилами:

<set function specification> ::= COUNT(*) |<distinct set function> |<all set function> <distinct set function> ::= { AVG MAX MIN SUM COUNT } (DISTNICT <column specification>) <all set function> ::= { AVG MAX MIN SUM } ([ALL] <value expression>)

Как видно из этих правил, в стандарте SQL/89 определены пять стандартных агрегатных функций: COUNT - число строк или значений, MAX - максимальное значение, MIN - минимальное значение, SUM - суммарное значение и AVG - среднее значение.



Базовая таблица INFORMATION_SCHEMA_CATALOG_NAME


Эта таблица специфицирует каталог информационной схемы. Таблица определяется следующим образом:

CREATE TABLE INFORMATION_SCHEMA_CATALOG_NAME (CATALOG_NAME SQL_IDENTIFIER, CONSTRAINT INFORMATION_SCHEMA_CATALOG_NAME_PRIMARY_KEY PRIMARY KEY (CATALOG_NAME))

Пояснения:

Значением столбца CATALOG_NAME является имя каталога, в котором располагается информационная схема. Определяется утверждение целостности INFORMATION_SCHEMA_CATALOG_ NAME_CARDINALITY, гарантирующее, что в таблице INFORMATION_SCHEMA_ CATALOG_NAME содержится ровно одна строка:

CREATE ASSERTION INFORMATION_SCHEMA_CATALOG_NAME_CARDINALITY CHECK (1 = (SELECT COUNT(*) FROM INFORMATION_SCHEMA_CATALOG_NAME))



Битовые строки


Битовая строка - это последовательность бит, каждый из которых имеет значение 0 или 1. Длиной битовой строки называется число битов в этой строке (0 или положительное целое число). При определении конкретного типа битовых строк указывается длина (в случае BIT) или максимальная длина строки (в случае BITVARYING).

Над битовыми строками определен ряд операций. Некоторые из них мы рассмотрим.

К операторам, которые работают с операндами - битовыми строками и возвращают битовые строки, относятся следующие:

Битовая конкатенация (обозначается в виде ), которая возвращает результирующую битовую строку, полученную путем конкатенации строк-операндов в том порядке, в котором они заданы. Функция извлечения подстроки из битовой строки. Синтаксис и семантика этой функции идентичны синтаксису и семантике функции SUBSTRING для символьных строк за исключением того, что первый аргумент и возвращаемое значение являются битовыми строками. Выражение длины возвращает длину заданной битовой строки в октетах или битах в зависимости от выбранной функции. Выражение позиции определяет первую позицию в битовой строке S, с которой в нее входит строка S1. Если строка S1 не входит в строку S, возвращается значение нуль.

Численные типы SQL/92 не отличаются от аналогичных типов SQL/89 за исключением того, что они более точно и подробно определяются в новом стандарте.



Численные выражения


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

<numeric value expression> ::= <term> |<numeric value expression> <plus sign> <term> |<numeric value expression> <minus sign> <term> <term> ::= <factor> |<term> <asterisk> <factor> |<term> <solidus> <factor> <factor> ::= [ <sign> ] <numeric primary> <numeric primary> ::= <value expression primary> |<numeric value function>

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

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

<numeric value function> ::= <position expression> |<extract expression> |<length expression> <position expression> ::= POSITION <left paren> <character value expression> IN <character value expression> <right paren> <length expression> ::= <char length expression> |<octet length expression> |<bit length expression> <char length expression> ::= { CHAR_LENGTH | CHARACTER_LENGTH } <left paren> <string value expression> <right paren> <octet length expression> ::= OCTET_LENGTH <left paren> <string value expression> <right paren> <bit length expression> ::= BIT_LENGTH <left paren> <string value expression> <right paren> <extract expression> ::= EXTRACT <left paren> <extract field> FROM <extract source> <right paren> <extract field> ::= <datetime field> |<time zone field> <time zone field> ::= T IMEZONE_HOUR |TIMEZONE_MINUTE <extract source> ::= <datetime value expression> |<interval value expression>

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



Динамический SQL


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

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

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

3.11.1. Оператор выделения памяти под дескриптор

<allocate descriptor statement> ::= LLOCATE DESCRIPTOR <descriptor name> [WITH MAX <occurrences>] <occurrences> ::= <simple value specification> <descriptor name> ::= (<scope option>] <simple value specification> scope option> ::= GLOBAL | LOCAL <simple value specification> ::= parameter name> (<embedded variable name> (<literal>


Пояснения:

Дескриптор - это динамически выделяемая часть памяти прикладной программы, служащая для принятия информации о результате или параметрах динамически подготовленного оператора SQL или задания параметров такого оператора. Смысл того, что для выделения памяти используется оператор SQL, а не просто стандартная функция alloc или какая-нибудь другая функция динамического запроса памяти, состоит в том, что прикладная программа не знает структуры дескриптора и даже его адреса. Это позволяет не привязывать SQL к особенностям какой-либо системы программирования или ОС. Весь обмен информацией между собственно прикладной программой и дескрипторами производятся также с помощью специальных операторов SQL (GET и SET, см. ниже).

Второй вопрос: зачем вообще выделять память под дескрипторы динамически? Это нужно потому, что в общем случае прикладная программа, использующая динамический SQL, не знает в статике число одновременно действующих динамических операторов SQL, описание которых может потребоваться. С этим же связано то, что имя дескриптора может задаваться как литеральной строкой символов, так и через строковую переменную включающего языка, т.е. его можно генерировать во время выполнения программы.

В операторе ALLOCATEDESCRIPTOR, помимо прочего, может указываться число описательных элементов, на которое он рассчитан. Если, например, при выделении памяти под дескриптор в разделе WITHMAX указано целое положительное число N, а потом дескриптор ис пользуется для описания M (M>N) элементов (например, M столбцов результата запроса), то это приводит к возникновению исключительной ситуации.


Домен CARDINAL_NUMBER


Домен содержит неотрицательные целые числа. Его определение:

CREATE DOMAIN CARDINAL_NUMBER AS INTEGER CONSTRAINT CARDINAL_NUMBER_DOMAIN_CHECK CHECK (VALUE >= 0)

Пояснение: целые числа, входящие в этот домен, не превышают определяемого в реализации максимально допустимого значения целого числа (определяемого в реализации значения NUMERIC_PRECISION_RADIX в степени определяемого в реализации значения NUMERIC_PRECISION).



Домен CHARACTER_DATA


Этот домен содержит все символьные данные. Определение выглядит следующим образом:

CREATE DOMAIN CHARACTER_DATA AS CHARACTER VARYING (ML) CHARACTER SET SQL_TEXT

Пояснение: ML обозначает определяемую в реализации максимально допустимую длину строки переменной длины.



Домен SQL_IDENTIFIER


В этом домене содержатся все допустимые идентификаты. Домен определяется следующим образом:

CREATE DOMAIN SQL_IDENTIFIER AS CHARACTER VARYING (L) CHARACTER SET SQL_TEXT

Пояснения:

Домен специфицирует все символьные строки переменного размера, которые соответствуют правилам формирования SQL-идентификатора; средствами SQL невозможно определить ограничение домена, которое было бы истинно для допустимых идентификаторов и ложно для других значений. L обозначает определяемую в реализации максимально допустимую длину идентификатора.



Домены, столбцы, таблицы, ограничения целостности


Домен является определенным и именованным в схеме множеством допустимых значений данного типа. Назначение домена состоит в том, чтобы ограничить множество значений связанного с ним типа, которые могут храниться в базе данных.

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

Столбец - это именованное мультимножество значений, которое может изменяться во времени. Все значения одного столбца относятся к одному типу данных или домену и являются значениями одной таблицы. Значение столбца - минимальный элемент данных, который может быть выбран из таблицы, и минимальный элемент данных, который может модифицироваться.

Для каждого столбца при его определении задается специальная характеристика, ограничивающая или допускающая появление в нем неопределенных значений. Попытка поместить неопределенное значение в столбец, для которого они запрещены, воспринимается как ошибка. Пусть C - имя столбца. В столбце С не могут быть разрешены неопределенные значения в любом из следующих трех случаев: (1) для содержащей его таблицы определено хотя бы одно неоткладываемое ограничение целостности с условием поиска, включающем С ISNOTNULL; (2) столбец определен на домене с неоткладываемым ограничением, содержащем фразу VALUESNOTNULL; (3) для столбца определено неоткладываемое ограничение уникальности, специфицирующее столбец как первичный ключ. Во всех остальных случаях в столбце могут быть разрешены неопределенные значения.

Таблица - это мультимножество строк. Строка - непустая последовательность значений. Каждая строка таблицы имеет одну и ту же мощность и содержит значения каждого столбца таблицы. i-тое значение каждой строки таблицы является значением ее i-того столбца. Строка является наименьшей единицей данных, которую можно вставить в таблицу и удалить из нее.

Степень таблицы - это число ее столбцов. В любой момент времени степень таблицы совпадает с мощностью любой из входящих в нее строк, а мощность таблицы совпадает с мощностью любого из ее столбцов. Пустой таблицей называется таблица с мощностью 0.

Таблица может быть базовой, представляемой или порождаемой. Базовая таблица может быть постоянно хранимой, глобальной временной, создаваемой локальной временной или объявляемой локальной временной. Постоянная базовая таблица - это именованная таблица, в определении которой не указано TEMPORARY.

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

Представляемая таблица - это именованная порождаемая таблица, определенная с помощью конструкции определения представления. Иногда представляемые таблицы называют просто представлениями.

Все базовые таблицы являются обновляемыми. Порожденные таблицы - либо обновляемые, либо только читаемые.

Глобальная временная таблица - именованная таблица, в определении которой указано GLOBALTEMPORARY. Создаваемая локальная временная таблица - именованная таблица, в определении которой указано LOCALTEMPORARY. Глобальные и создаваемые временные таблицы реально материализуются (т.е. начинают занимать память) только при обращении к ним в SQL-сессии, причем для локальных временных таблиц создаются отдельные экземпляры для каждого модуля, участвующего в сессии.

Объявляемая локальная временная таблица - именованная локальная таблица, которая реально материализуется при первом выполнении любой процедуры в модуле, содержащем объявление временной таблицы, и доступна только процедурам этого модуля. Образ такой таблицы во внешней памяти не сохраняется после конца SQL-сессии, в которой эта таблица была материализована.

Ограничения целостности, обычно называемые просто ограничениями, определяют допустимые состояния базы данных, ограничивая возможные значения базовых таблиц. Ограничение - это либо ограничение таблицы, либо ограничение домена, либо утверждение целостности. Для каждого ограничения известно его имя, откладываемое ли оно, является ли начальный режим ограничения откладываемым или же немедленным.

Выражение запроса или спецификация запроса является возможно недетерминированным, если реализация может в два разных момента времени при одном и том же состоянии базы данных произвести результаты, различающиеся не только порядком строк. Никакое ограничение целостности не должно использовать недетерминированные выражения или спецификации запроса.

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

Проверка ограничения производится в зависимости от его режима в текущей транзакции. Если режим немедленный, то ограничение проверяется в конце каждого оператора. Если режим отложенный, то ограничение проверяется либо при изменении режима на немедленный, либо в конце текущей транзакции.

Когда ограничение проверяется не в конце транзакции и не удовлетворяется, то возбуждается исключительная ситуация, и SQL-оператор, вызвавший проверку ограничения, не производит никакого действия, кроме занесения соответствующей информации в область диагностики. При завершении транзакции (выполнении оператора COMMIT) фактически проверяются все ограничения; если какое-либо ограничение не удовлетворяется, транзакция завершается откатом (неявным выполнением оператора ROLLBACK).

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

Ограничение домена применяется ко всем столбцам, определенным на данном домене, и ко всем значениям, преобразуемым к этому домену. Ограничение домена содержит условие поиска и удовлетворяется в том и только в том случае, когда для любой таблицы T, которая содержит столбец C, основанный на этом домене, условие поиска с заменой каждого вхождения VALUE на C не является ложным для каждой строки T. Ограничение домена удовлетворяется результатом операции преобразования в том и только в том случае, когда условие поиска с заменой каждого вхождения VALUE на этот результат не является ложным.

Ограничение целостности - это именованное ограничение, которое может относиться к содержимому отдельных строк таблицы, ко всему содержимому таблицы или к состоянию, которым должен обладать набор таблиц. Ограничение целостности содержит условие поиска и удовлетворяется в том и только в том случае, когда это условие поиска не является ложным.



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


Внешне предикаты, которые можно использовать в условиях поиска 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>

Пояснения:

Строки-операнды должны быть одинаковой степени. Типы данных соответствующих значений строк-операндов должны быть совместимы. Пусть X и Y обозначают соответствующие элементы строк-операндов, а XV и YV - их значения

(a) если XV и/или YV являются неопределенными значениями, то значение условия "X <compop> Y" есть unknown;

(b) если XV и YV не являются неопределенными значениями, то значением условия "X <compop> Y" является true или false в соответствии с естественными правилами применения операции сравнения.

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


(a) если длина в символах строки X не равна длине строки Y, то для выравнивания длин строк более короткая строка расширяется символом набивки (padsymbol); если не используется явно специфицируемый порядок сортировки для используемого набора символов, то в качестве символа набивки используется пробел;

(b) далее производится лексикографическое сравнение строк в соответствии с предопределенным или явно определенным порядком сортировки символов.



Сравнение двух битовых строк X и Y основано на сравнении соответствующих бит. Если Xi и Yi - значения i-тых бит X и Y соответственно и если LX и LY обозначает длину в битах X и Y соответственно, то

(a) X равно Y тогда и только тогда, когда LX = LY и Xi = Yi для всех i;

(b) X меньше Y тогда и только тогда, когда

(i) LX < LY и Xi = Yi для всех i меньших или равных LX, или

(ii) Xi = Yi для всех i < n и Xn = 0, а Yn =1 для некоторого n меньшего или равного min (LX,LY).



Сравнение двух значений типа дата-время производится в соответствии с видом интервала, получающегося при вычитании второго значения из первого. Пусть X и Y - сравниваемые значения, а H - наименее значимое поле даты-времени X и Y. Результат сравнения X <compop> Y определяется как (X - Y) H <compop> INTERVAL (0) H. (Два значения типа дата-время сравнимы только в том случае, если они содержат одинаковый набор полей даты-времени.) Пусть Rx и Ry обозначают строки-операнды, а RXi и RXi - i-тые элементы Rx и Ry соответственно. Результат сравнения "Rx <compop> Ry" определяется следующим образом:

(a) "Rx = Ry" есть true тогда и только тогда, когда RXi = RYi для всех i;

(b) "Rx <> Ry" есть true тогда и только тогда, когда RXi <> RYi для некоторого i;

(c) "Rx < Ry" есть true тогда и только тогда, когда RXi = RYi для всех i < n, и RXn < RYn для некоторого n;

(d) "Rx > Ry" есть true тогда и только тогда, когда RXi = RYi для всех i < n, и RXn > RYn для некоторого n;



(e) "Rx <= Ry" есть true тогда и только тогда, когда Rx = Ry или Rx < Ry;

(f) "Rx >= Ry" есть true тогда и только тогда, когда Rx = Ry или Rx > Ry;

(g) "Rx = Ry" есть false тогда и только тогда, когда "Rx <> Ry" есть true.

(h) "Rx <> Ry" есть false тогда и только тогда, когда "Rx = Ry" есть true.

(i) "Rx < Ry" есть false тогда и только тогда, когда "Rx >= Ry" есть true.

(j) "Rx > Ry" есть false тогда и только тогда, когда "Rx <= Ry" есть true.

(k) "Rx <= Ry" есть false тогда и только тогда, когда "Rx > Ry" есть true.

(l) "Rx >= Ry" есть false тогда и только тогда, когда "Rx < Ry" есть true.

(m) "Rx <compop> Ry" есть unknown тогда и только тогда, когда "Rx <compop> Ry" не есть true или false.




Информационная схема и каталоги базы данных


Информационная схема (InformationSchema) содержит описание структуры базы данных в виде набора представлений, определенных над базовыми таблицами, которые в свою очередь определены в отдельной схеме определений (DefinitionSchema). Единственное назначение схемы определений состоит в том, чтобы обеспечить модель для поддержки информационной схемы и облегчить ее понимание. От реализации требуется не более того, как моделировать существование схемы определений, чтобы можно было поддерживать представления информационной схемы.

Таблицы информационной схемы определяются как содержащиеся в схеме с именем INFORMATION_SCHEMA. Эти таблицы доступны пользователям как любые другие таблицы в любой другой схеме. Привилегия SELECT для всех этих представлений предоставлена PUBLIC с правом передачи привилегии. В результате любой пользователь может адресовать представлениям информационной схемы свои запросы и разрешать или запрещать другим пользователям доступ к представлениям, определенным на основе представлений информационной схемы. Другие привилегии на эти представления не передаются, поэтому пользователи не могут выполнять над ними операции обновления. Кроме того, информационная схема содержит определения ряда доменов, использование которых с правом передачи привилегии на использование доступно всем пользователям.

В реализации могут определяться дополнительные объекты информационной схемы, а также к определенным с стандарте представлениям могут добавляться столбцы.

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

3.13.1. Информационная схема

Определение информационной схемы выглядит следующим образом:

CREATE SCHEMA INFORMATION_SCHEMA AUTHORIZATION INFORMATION_SCHEMA



История языка SQL


История наиболее распространенного в настоящее время языка реляционных баз данных SQL насчитывает уже более 25 лет. Первый, достаточно полный функционально, но не полностью синтаксически и семантически определенный вариант языка SQL (его исходным названием было SEQUEL - StructuredEnglishQueryLanguage) был разработан и частично реализован в рамках проекта экспериментальной реляционной СУБД SystemR (проект выполнялся с 1974 по 1979 гг. в научно-исследовательской лаборатории компании IBM в г. Сан-Хосе, Калифорния).

Название языка SQL (StructuredQueryLanguage - структурированный язык запросов) только частично отражает его суть. Конечно, язык всегда был главным образом ориентирован на удобную и понятную пользователям формулировку запросов к реляционной БД, но на самом деле с самого начала задумывался как полный язык БД. Под этим мы понимаем то, что (по крайней мере, теоретически) знание SQL полностью достаточно для выполнения любых осмысленных действий с базой данных, управляемой SQL-ориентированной СУБД. Помимо операторов формулирования запросов и манипулирования БД язык содержит:

средства определения схемы БД и манипулирования схемой; операторы для определения ограничений целостности и триггеров; средства определения представлений БД; средства авторизации доступа к отношениям и их полям; средства управления транзакциями.

Другими словами, язык SQL претендует на то, что он способен полностью представить реляционную модель данных, т.е. его средств достаточно для представления всех аспектов реляционных баз данных в терминах Кодда. (Сразу заметим, что с этим утверждением многие несогласны, полагая, что некоторые возможности SQL расширяют классическую реляционную модель, а некоторые другие возможности - ее ограничивают.)

Вместе с тем, несмотря на многолетнюю историю языка, для многих начинающих пользователей современных реляционных СУБД (включая разработчиков информационных систем) подчас трудно понять, можно ли говорить о языке SQL как таковом (в том смысле, в котором можно говорить о языках программирования Си или Паскаль, не привязываясь к их конкретной реализации) или же существует столько разнообразных вариантов SQL, сколько имеется разных SQL-ориентированных СУБД. Нужно сказать, что этот вопрос остается трудным, и ответить на него полностью однозначно не удается. Действительно, сегодня, видимо, невозможно найти две реализации, в которых диалекты SQL полностью бы совпадали.

Но на самом деле то же относится и к разным реализациям языков программирования (сравните, например, реализационные диалекты языка Си компиляторов Borland и GCC). Важно другое. Существует международный стандарт языка Си (ANSI/ISOC), который должен поддерживаться в любом компиляторе, претендующем на совместимость со стандартом (хотя реализационный диалект языка может содержать существенные расширения). Именно наличие стандарта языка Си в совокупности с другими стандартами Открытых Систем обеспечивает возможность создания легко переносимых прикладных (и иногда и системных) программ.

После появления в 1989 г. первого международного стандарта языка SQL (SQL-89) и, в особенности, после принятия в 1992 г. второго международного стандарта SQL-92 стало возможным говорить про стандартную среду SQL-ориентированной СУБД. Для грамотного использования любой SQL-ориентированной реляционной СУБД знание стандартов языка кажется необходимым.



Изменение схемы таблицы


Добавьте к таблице my_libn столбец с именем added типа char(5) со значением по умолчанию 'empty'.

Вставьте в таблицу еще две строки, одна из которых содержит значение столбца added, а другая - нет. Просмотрите содержимое таблицы. Просмотрите содержимое представления.



Язык баз данных SQL/


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


Стандарт имеет следующую структуру:

Раздел 1: "Область применения";

Раздел 2: "Нормативные ссылки" - перечень дополнительных стандартов;

Раздел 3: "Определения, обозначения и соглашения";

Раздел 4: "Понятия" - базовые понятия, используемые при определении языка;

Раздел 5: "Лексические элементы";

Раздел 6: "Скалярные выражения" - определение элементов языка, производящих скалярные значения;

Раздел 7: "Выражения запросов" - определение элементов языка, производящих строки и таблицы данных;

Раздел 8: "Предикаты";

Раздел 9: "Правила присваивания данных" - правила, определяющие порядок выборки данных из базы данных или сохранения данных в базе данных, и правила формирования операций над множествами;

Раздел 10: "Дополнительные общие элементы" - дополнительные общие языковые элементы, используемые в разных частях языка;

Раздел 11: "Определение схемы и манипулирование схемой" - определение средств создания схемы и управления схемой;

Раздел 12: "Модуль" - определение модулей и процедур;

Раздел 13: "Манипулирование данными" - определение операторов манипулирования данными;

Раздел 14: "Управление транзакциями";

Раздел 15: "Управление подключениями";

Раздел 16: "Управление сессиями";

Раздел17: "Динамический SQL" - определение средств, предназначенных для динамического выполнения операторов SQL;

Раздел 18: "Управление диагностикой"

Раздел 19: "Встроенный SQL" - определение синтаксиса встраивания SQL в некоторые стандартные языки программирования;

Раздел 20: "Прямой вызов SQL" - определение подмножества SQL/92, которое может использоваться в режиме прямого вызова;

Раздел21: "Информационная схема и схема определений" - определение представляемых таблиц, содержащих информацию о схеме;

Раздел22: "Коды статуса" - определение значений, идентифицирующих статус завершения SQL-операторов, и механизмов, посредством которых эти значения возвращаются;



Раздел 23: "Соответствие" - определение критериев соответствия языку SQL/92;

Далее следует набор приложений, которые не являются частью стандарта, а предназначены только для информирования пользователей и разработчиков.

Приложение A: "Уровни языка SQL" - перечисление правил, определяющих подмножества вводного SQL (EntrySQL) и промежуточного SQL (IntermediateSQL) стандарта SQL/92;

Приложение B: "Элементы, определяемые в реализации" - перечисление средств, для которых в стандарте установлено, что синтаксис, или смысл, или результат воздействия на базу данных частично или полностью определяется в реализации, и описание определяющей информации, которая должна быть обеспечена в реализации для каждого случая;

Приложение C: "Элементы, зависимые от реализации" - перечисление средств, для которых в стандарте явно установлено, что их смысл или результат воздействия на базу данных зависит от реализации;

Приложение D: "Неодобряемые свойства" - перечисление свойств, которые разработчики стандарта не хотели бы видеть в его следующей версии;

Приложение E: "Несовместимости с SQL/89" - перечисление несовместимостей между SQL/92 и SQL/89;

Приложение F: "Поддержка и интерпретация SQL" - разъясняются интерпретации SQL и коррективы, которые были внесены после принятия SQL/89.

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


Язык модулей и встроенный SQL


В стандарте SQL/89 определены два способа взаимодействия с БД из прикладной программы, написанной на традиционном языке программирования (как мы уже упоминали, SQL/89 ориентирован на использование совместно с языками Кобол, Фортран, Паскаль и ПЛ/1, но в реализациях обычно поддерживается и язык Си). Первый способ состоит в том, что все операторы SQL, с которыми может работать данная прикладная программа, собраны в один модуль и оформлены как процедуры этого модуля. Для этого SQL/89 содержит специальный подъязык - язык модулей. При использовании такого способа взаимодействия с БД прикладная программа содержит вызовы процедур модуля SQL с передачей им фактических параметров и получением ответных параметров.

Второй способ состоит в использовании так называемого встроенного SQL, когда с использованием специального синтаксиса в программу на традиционном языке программирования встраиваются операторы SQL. В этом случае с точки зрения прикладной программы оператор SQL выполняется "по месту". Явная параметризация операторов SQL отсутствует, но во встроенных операторах SQL могут использоваться имена переменных основной программы, и за счет этого обеспечивается связь между прикладной программой и СУБД.

Концептуально эти два способа эквивалентны. Более того, в стандарте устанавливаются правила порождения неявного модуля SQL по программе со встроенным SQL. Однако в большинстве реализаций операторы SQL, содержащиеся в модуле SQL, и встроенные операторы SQL обрабатываются существенно по-разному. Модуль SQL обычно компилируется отдельно от прикладной программы, в результате чего порождается набор так называемых хранимых процедур (в стандарте этот термин не используется, но распространен в коммерческих реализациях). Т.е. в случае использования модуля SQL компиляция операторов SQL производится один раз, и затем соответствующие процедуры сколько угодно раз могут вызываться из прикладной программы.

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

Конечно, пользователи не обязаны знать об этом техническом различии в обработке двух видов взаимодействия с СУБД. Существуют и такие системы, которые производят одноразовую компиляцию встроенных операторов SQL и сохраняют откомпилированный код (например, СУБД семейства DB2 компании IBM). Но все-таки лучше иметь это в виду.

Приведем некоторые соображения за и против каждого из этих двух способов. При использовании языка модулей текст прикладной программы имеет меньший размер, взаимодействия с СУБД более локализованы за счет наличия явных параметров вызова процедур. С другой стороны, для понимания смысла поведения прикладной программы потребуется одновременное чтение двух текстов. Кроме того, как кажется, синтаксис модуля SQL может существенно различаться в разных реализациях. Встроенный SQL предоставляет возможность производства более "самосодержащихся" прикладных программ. Имеется больше оснований рассчитывать на простоту переноса такой программы в среду другой СУБД, поскольку стандарт встраивания более или менее соблюдается. Основным недостатком является некоторый PL-подобный вид таких программ, независимо от выбранного основного языка. И конечно, нужно учитывать замечания, содержащиеся в предыдущих абзацах.

Далее мы коротко опишем язык модулей и правила встраивания в соответствии со стандартом SQL/89 (еще раз заметим, что формально правила встраивания не являются частью стандарта).


2.5.1. Язык модулей

Структура модуля SQL в стандарте SQL/89 определяется следующими синтаксическими правилами:

<module> ::= <module name clause> <language clause> <module authorization clause> [<declare cursor>...] < procedure > ... <module name clause> ::= MODULE [<module name>] <language clause> ::= LANGUAGE { COBOL FORTRAN PASCAL PLI } <module authorization clause> ::= AUTHORIZATION <module authorization identifier> <module authorization identifier> ::= <authorization identifier>

Существенно, что каждый модуль SQL ориентирован на использование в программах, написанных на конкретном языке программирования. Если в модуле присутствуют процедуры работы с курсорами, то все курсоры должны быть специфицированы в начале модуля. Заметим, что объявление курсора не погружается в какую-либо процедуру, поскольку это описательный, а не выполняемый оператор SQL.


Этапы стандартизации SQL


Работа по стандартизации языка SQL началась практически одновременно с появлением первых его коммерческих реализаций. В качестве стандарта нельзя было использовать SQLSystemR. Этот вариант языка не был должным образом технически проработан и, кроме того, его слишком сложно было бы реализовать. С другой стороны, первые коммерческие реализации языка настолько различались, что ни один из реализованных диалектов не имел шансов быть принятым в качестве стандарта. В частности, это относится и к первому корпоративному стандарту языка, принятому компанией IBM.

Принятый в 1989 г. [ISO89] Международный Стандарт SQL (SQL/89) во многих частях имеет чрезвычайно общий характер и допускает очень широкое толкование. В этом стандарте полностью отсутствуют такие разделы как манипулирование схемой БД и динамический SQL. Многие существенные аспекты языка в соответствии со стандартом определяются в реализации.

Поэтому на фоне завершения разработки этого стандарта была начата работа над стандартом SQL2. Она также длилась несколько лет, пока, наконец, в марте 1992г. не был выработан окончательный проект стандарта [ISO92] (теперь его принято называть SQL/92). Этот стандарт существенно более полный и охватывает практически все необходимые для реализации аспекты: манипулирование схемой БД, управление транзакциями и сессиями (сессия - это последовательность транзакций, в пределах которой сохраняются временные отношения), подключение к БД, динамический SQL. Cтандартизованы также отношения-каталоги БД, которые хотя и не связаны с языком непосредственно, но сильно влияют на реализацию.

Одновременно с завершением работ по определению стандарта SQL2 была начата разработка стандарта SQL3. Предполагается, что SQL3 будет содержать механизм триггеров и возможность использования абстрактных типов данных. Принятие стандарта планируется в 1999 г.



Манипулирование данными


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

3.6.1. Операторы, связанные с курсором

Для объявления курсора используется конструкция, определяемая следующими синтаксическими правилами:

<declare cursor> ::= DECLARE <cursor name> [ INSENSITIVE ] [ SCROLL ] CURSOR FOR <cursor specification> <cursor specification> ::= <query expression> [ <order by clause> ] [ <updatability clause> ] <updatability clause> ::= FOR { READ ONLY | UPDATE [ OF <column name list> ] } <order by clause> ::= ORDER BY <sort specification list> <sort specification list> ::= <sort specification> [ { <comma> <sort specification> }... ] <sort specification> ::= <sort key> [ <collate clause > ] [ <ordering specification> ] <sort key> ::= <column name> <unsigned integer> <ordering specification> ::= ASC DESC

Пояснения:

Пусть T обозначает таблицу, получаемую при вычислении выражения запроса, которое входит в спецификацию курсора. Если раздел обновляемости курсора (updatabilityclause) не специфицирован, то

(a) если спецификация курсора содержит ключевые слова INSENSITIVE, SCROLL или ORDERBY или если T является только читаемой таблицей, то по умолчанию предполагается задание раздела обновляемости с ключевым словом READONLY;

(b) в противном случае неявно предполагается указание раздела обновляемости с ключевым словом FORUPDATE и без списка имен столбцов (т.е. предполагается, что изменения могут относиться ко всем столбцам T).




Если T является обновляемой таблицей, то пусть TU обозначает базовую таблицу, на которой в конечном счете базируется вычисление выражения запроса. Если в спецификации сортировки содержится раздел задания порядка сортировки (collateclause), то столбец сортировки должен иметь тип данных символьных строк. Если специфицирован раздел обновляемости с FORUPDATE и явным или неявным указанием списка имен столбцов, то таблица T должна быть обновляемой, и спецификация курсора не должна содержать ключевого слова INSENSITIVE. Если раздел обновляемости с FORUPDATE без списка имен столбцов специфицирован или неявно подразумевается, то по умолчанию предполагается наличие списка имен столбцов, включающего имена каждого столбца TU. Если специфицирован раздел обновляемости с FORUPDATE со списком имен столбцов, каждое имя в этом списке должно быть именем столбца TU. Если T является обновляемой таблицей, то для каждой строки T, существует в точности одна соответствующая строка TU, из которой порождена эта строка T. Спецификация INSENSITIVE означает, что после открытия курсора изменения, производимые в той же транзакции над строками таблицы TU, не должны оказывать влияния на состояние таблицы T; спецификация SCROLL означает, что после открытия курсора разрешается произвольное изменение его позиции.

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

<open statement> ::= OPEN <cursor name>

Пояснения:

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

(a) создается копия S, и в ней все вхождения спецификации цели (имена параметров или внешних переменных) заменяются на соответствующие значения, а также символические константы и вызовы функций даты времени заменяются на соответствующие текущие значения;

(b) пусть T обозначает таблицу, специфицированную копией S;

(c) создается описатель этой таблицы и заполняется в соответствии с особенностями спецификации курсора;

(d) если S содержит INSENSITIVE, то создается копия T, курсор переводится в открытое состояние, и его позиция устанавливается перед первой строкой копии T;



(e) в противном случае курсор переводится в открытое состояние, и его позиция устанавливается перед первой строкой T.



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

<fetch statement> ::= FETCH [ [ <fetch orientation> ] FROM ] <cursor name> INTO <fetch target list> <fetch orientation> ::= NEXT |PRIOR |FIRST |LAST { ABSOLUTE | RELATIVE } <simple value specification> <fetch target list> ::= <target specification> [ { <comma> <target specification> }... ]

Пояснения:

Если отсутствует указание ориентации чтения (fetchorientation), неявно предполагается наличие ориентации NEXT. Если неявная или явная ориентация отличается от NEXT, то в объявлении курсора должна присутствовать спецификация SCROLL. Если в указании ориентации чтения присутствует спецификация простого значения, то тип данных этого значения должен быть типом точных чисел с масштабом 0. Определим J следующим образом:

(a) если в указании ориентации чтения содержится спецификация простого значения, то пусть J равняется этому значению;

(b) если в указании ориентации присутствует NEXT или FIRST, то пусть J равняется +1;

(c) если в указании ориентации присутствует PRIOR или LAST, то пусть J равняется -1.



Пусть Tt обозначает таблицу той же степени, что таблица T, соответствующая результату спецификации курсора; тогда

(a) если в указании ориентации присутствует ABSOLUTE, FIRST или LAST, то пусть Ttсодержит все строки T с сохранением их порядка;

(b) если в указании ориентации присутствует NEXT или RELATIVE с положительным значением J, то

(i) если таблица T пуста или если позиция курсора установлена на последнюю строку T или за ней, то пусть Tt будет пустой таблицей;

(ii) если позиция курсора установлена на строку R, не являющуюся последней строкой T, то пусть Tt содержит все строки T, стоящие по порядку за R, с сохранением их порядка в T;

(iii) если позиция курсора установлена перед строкой R, то пусть Tt содержит строку R и все строки T, стоящие по порядку за R, с сохранением их порядка в T;



(c) если в указании ориентации присутствует PRIOR или RELATIVE с отрицательным значением J, то

(i) если таблица T пуста или если позиция курсора установлена на первую строку T или перед ней, то пусть Tt будет пустой таблицей;

(ii) если позиция курсора установлена на строку R, не являющуюся первой строкой T, то пусть Tt содержит все строки T, стоящие по порядку перед R, с сохранением их порядка в T;

(iii) если позиция курсора установлена перед строкой, следующей по порядку за R, то пусть Tt содержит строку R и все строки T, стоящие по порядку перед R, с сохранением их порядка в T;

(iv) если позиция курсора установлена после последней строки T, то пусть Tt содержит все строки T с сохранением их порядка.

(d) если специфицировано RELATIVE с нулевым значением J, то

(i) если позиция курсора установлена на строку таблицы T, то пусть Tt включает одну эту строку;

(ii) в противном случае, пусть Tt будет пустой таблицей.



Пусть N обозначает число строк в Tt. Если J положительно, то пусть K равняется J. Если J отрицательно, то пусть K равняется N+J+1. Если J равно нулю, и специфицировано ABSOLUTE, то пусть K равняется нулю; если же J равно нулю, и специфицировано RELATIVE, то пусть K равняется 1. Операция чтения выполняется следующим образом:

(a) если K больше нуля и не больше N, то курсор позиционируется на K-тую строку Tt и соответствующую строку T; эта строка становится текущей строкой курсора;

(b) В противном случае целям, указанным в списке целей чтения, не присваиваются никакие значения и вырабатывается условие завершения "нет данных"; при этом

(i) если специфицирована ориентация RELATIVE с нулевым значением J, то позиция курсора не меняется;

(ii) если явно или неявно специфицирована ориентация NEXT, либо специфицирована ориентация ABSOLUTE или RELATIVE с K, большим чем N, либо специфицирована ориентация LAST, то курсор позиционируется за последней строкой;

(iii) в противном случае, курсор позиционируется перед первой строкой.

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



<delete statement: positioned> ::= DELETE FROM <table name> WHERE CURRENT OF <cursor name>

В принципе, оператор и выполняется так же, как предписано в SQL/89, однако в стандарте SQL/92 приводятся некоторые уточнения поведения оператора:

Если текущая транзакция имеет режим доступа "только чтение" и таблица, из которой удаляется кортеж не является временной, то возбуждается исключительное условие. Текущая строка помечается для удаления. Если оказалось, что помечаемая строка уже помечена для удаления оператором поискового удаления или оператором позиционного удаления, связанным с другим курсором, или помечена для обновления оператором поисковой модификации или оператором позиционной модификации, связанным с другим курсором, то в условии завершения текущего оператора сообщается соответствующее предупреждение. Строка, помеченная для удаления, реально удаляется в конце выполнения оператора позиционного удаления до проверки каких-либо ограничений целостности. Если удаляется последний кортеж, то курсор устанавливается в позицию после последней строки; в противном случае курсор устанавливается в позицию перед следующей строкой.

Оператор позиционной модификации также мало отличается от соответствующего оператора SQL/89:

<update statement: positioned> ::= UPDATE <table name> SET <set clause list> WHERE CURRENT OF <cursor name> <set clause list> ::= <set clause> [ { <comma> <set clause> }... ] <set clause> ::= <object column> <equals operator> <update source> <update source> ::= <value expression> |<null specification> |DEFAULT <object column> ::= <column name>

Как и для оператора позиционного удаления, мы поясним только отличия и расширения по отношению к SQL/89:

Изменения, производимые с использованием упорядоченного курсора, не должны затрагивать столбцы сортировки; Если текущая транзакция выполняется в режиме только чтения, возбуждается исключительное условие. Будем называть объектной строкой ту строку, из которой порождена текущая строка курсора. Если оказалось, что к моменту выполнения операции позиционного обновления объектная строка уже помечена для удаления некоторым поисковым оператором удаления или позиционным оператором удаления, связанным с другим курсором, или если она помечена для обновления некоторым поисковым оператором обновления или поисковым оператором обновления, связанным с другим курсором, генерируется условие завершения с соответствующим предупреждением. Ключевое слово DEFAULT в разделе SET означает, что в соответствующий столбец обновляемой таблицы должно быть помещено его значение по умолчанию. Выражение, вырабатывающее значение, в разделе SET вычисляется до обновления объектной строки; если это выражение содержит ссылку на столбец изменяемой таблицы, то это рассматривается как ссылка на значение столбца до его изменения. Курсор остается позиционированным на текущую строку.

Оператор закрытия курсора в SQL/92 имеет такие же синтаксис и семантику, что и соответствующий оператор языка SQL/89.


Набор операторов манипулирования данными


В стандарте SQL/89 определен очень ограниченный набор операторов манипулирования данными. Их можно классифицировать на группы операторов, связанных с курсором; одиночных операторов манипулирования данными; и операторов завершения транзакции. Все эти операторы можно использовать как в модулях SQL, так и во встроенном SQL. Заметим, что в SQL/89 не определен набор операторов интерактивного SQL.

2.6.1. Операторы, связанные с курсором

Операторы этой группы объединяет то, что все они работают с некоторым курсором, объявление которого должно содержаться в том же модуле или программе со встроенным SQL.



Одной из проблем реализации языка


Одной из проблем реализации языка SQL всегда являлась проблема распознавания "изменяемости" соединений. Как известно, если представление включает соединение общего вида, то теоретически невозможно определить, можно ли однозначно интерпретировать операции обновления такого представления. Однако существует несколько важных классов соединений, которые заведомо являются изменяемыми. В SQL/3 предполагается выделить эти классы с помощью специальных синтаксических конструкций.

Наконец-то появляется возможность определения триггеров как комбинации спецификаций события и действия. Действие определяется как SQL-процедура, в которой могут использоваться как операторы SQL, так и ряд управляющих конструкций. На самом деле, этот механизм очень близок к тому, который реализован в OracleV.7 (и, конечно, в Oracle 8).

Что касается управления транзакциями, то происходит возврат к старой идее SystemR о возможности установки внутри транзакции точек сохранения (savepoints). В операторе ROLLBACK можно указать идентификатор ранее установленной точки сохранения, и тогда будет произведен откат транзакции не к ее началу, а к этой точке сохранения.

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


Несовместимости SQL/ и SQL/


Документ SQL/92 включает приложение, в котором устанавливаются несовместимости между SQL/92 и SQL/89. Мы перечислим эти несовместимости ниже.

В SQL/92 имеется более 100 дополнительных зарезервированных слов. Конкретные детали следует смотреть в самом стандарте. В SQL/89 модуль, происходящий из встроенного SQL, имел идентификатор авторизации, определяемый в реализации; в SQL/92 он вообще не имеет идентификатора авторизации. Имена параметров в SQL/89 не имели префикса в виде двоеточия. SQL/92 требует наличия такого префикса. SQL/89 допускает определение двух различных возможных ключей для одной базовой таблицы с заданием одного и того же набора столбцов. SQL/92 этого не допускает. SQL/89 не препятствует рекурсивному определению представления, т.е. в терминах его же самого. SQL/92 не допускает этой возможности. Семантика WITHCHECKOPTION была двусмысленной в SQL/89, но была прояснена в SQL/92. (По крайней мере, это утверждается в документе SQL/92. Более точно, опция проверки не являлась наследуемой в SQL/89, но является таковой в SQL/92 по умолчанию.) Пусть в спецификации курсора C отсутствует раздел GROUPBY, и пусть курсор C открывается несколько раз внутри одной и той же транзакции. В SQL/89 требуется, чтобы строки, доступные через курсор C, возвращались в одном и том же порядке при каждом открытии. В SQL/92 порядок при каждом открытии зависит от реализации и, следовательно, может отличаться для разных открытий курсора. В соответствии со стандартом SQL/89, если курсор установлен на некоторую строку или перед ней, и эта строка удаляется, курсор устанавливается перед следующей строкой или (если следующей строки нет) после последней строки. (Заметим, что это требование достаточно трудно удовлетворить в реализации.) В SQL/92 изменение состояния курсора определяется только если операция DELETE производится через тот же самый курсор; в противном случае воздействие на курсор зависит от реализации. В SQL/89 привилегия SELECT требовалась только для таблиц, к которым производится доступ через операторы FETCH или одиночный SELECT. В SQL/92 это дополнительно требуется для таблиц, упоминаемых в некоторых табличных выражениях, условных выражениях и скалярных выражениях.


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

Фактически, SQL/89 состоял из двух разных языков - языка модулей и языка определения схем. Операторы CREATETABLE, CREATEVIEW и GRANT могли появляться только как элементы внутри оператора CREATESCHEMA, и этот оператор в свою очередь был оператором языка определения схем; таким образом, CREATESCHEMA (и следовательно, CREATETABLE, CREATEVIEW и GRANT) не могли появляться внутри модуля. В попытке сохранить совместимость с этим достаточно странным обстоятельством, в стандарте SQL/92 многократно указывается, что оператор CREATESCHEMA мог бы не включаться в модуль; однако из описания языка не видно способа осуществить эту возможность. В SQL/89 привилегия REFERENCES требовалась только для возможных ключей, на которые ссылались некоторые внешние ключи. В SQL/92 это требуется для любого столбца, который встречается в некотором ограничении целостности. Стандарт SQL/89 допускает использование квалифицированных имен столбцов в разделе ORDERBY. SQL/92 этого не допускает. (На самом деле, это изменение лучше расценивать как исправление ошибки SQL/89, а не как несовместимость, поскольку в соответствии со спецификациями SQL/89 область видимости квалифицированного имени столбца не включала или, по крайней мере, не должна была включать раздел ORDERBY.) В соответствии со стандартом SQL/92 значением константы USER является текущий идентификатор авторизации. В SQL/89 значением USER должен являться идентификатор авторизации модуля. В SQL/89 квалификатором имени высшего уровня для (например) имен базовых таблиц был идентификатор авторизации. В SQL/92 это имя схемы, которое, в свою очередь, включает (возможно, неявное) имя каталога как другой (более высокого уровня) квалификатор.


Одиночные операторы


Основной набор одиночных операторов манипулирования данными и смысл этих операторов в SQL/92 не изменился (или незначительно изменился) по сравнению с SQL/89.

Одиночный оператор выборки в SQL/92 имеет следующий синтаксис:

<select statement: single row> ::= SELECT [ <set quantifier> ] <select list> INTO <select target list> <table expression> <select target list> ::= <target specification> [ { <comma> <target specification> }... ]

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

Оператор поискового удаления строк имеет точно такой же синтаксис, что и в SQL/89:

<delete statement: searched> ::= DELETE FROM <table name> [ WHERE <search condition> ]

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

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

(a) если условие поиска не специфицировано, то все строки таблицы помечаются для удаления;

(b) заданное условие поиска применяется для каждой строки указанной таблицы, и каждая строка, для которой условие поиска вычисляется в true, помечается для удаления.

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


Оператор поисковой модификации обладает почти таким же синтаксисом, что и соответствующий оператор в SQL/89, если не считать некоторых расширений раздела SET (для полноты мы повторим здесь синтаксическое определение конструкции <setclauselist>):

<update statement: searched> ::= UPDATE <table name> SET <set clause list> [ WHERE <search condition> ] <set clause list> ::= <set clause> [ { <comma> <set clause> }... ] <set clause> ::= <object column> <equals operator> <update source> <update source> ::= <value expression> | <null specification> | DEFAULT <object column> ::= <column name>

И в этом случае основные расширения по сравнению с SQL/89 относятся к более мощным возможностям определения условия поиска. Другие расширения и уточнения затрагивают следующее:

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

(a) если условие поиска не специфицировано, то все строки таблицы помечаются для модификации;

(b) заданное условие поиска применяется для каждой строки указанной таблицы, и каждая строка, для которой условие поиска вычисляется в true, помечается для модификации.



Как и в случае позиционных операторов обновления, если для некоторой строки обнаруживается, что она уже помечена для обновления (удаления или модификации) другим оператором (позиционным или поисковым), то в условии завершения оператора поисковой модификации возвращается предупреждение. Если набор объектных строк пуст, вырабатывается условие завершения "нет данных".

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

<insert statement> ::= INSERT INTO <table name> <insert columns and source> <insert columns and source> ::= [ <left paren> <insert column list> <right paren> ] <query expression> | DEFAULT VALUES <insert column list> ::= <column name list>



Пояснения относительно расширений и уточнений:

Если в разделе вставляемых столбцов и источников данных указано DEFAULTVALUES, то это эквивалентно заданию выражения запроса в форме VALUES(DEFAULT, . . .), где число элементов "DEFAULT" равно числу столбцов в таблице T, в которую заносится строка. Столбец, указанный в списке вставляемых столбцов, называется объектным. Если текущая транзакция выполняется в режиме только чтения и T не является временной таблицей, возбуждается исключительное условие. Выполнение оператора происходит так же, как это специфицировано в стандарте SQL/89.

Наконец, последним оператором, который в стандарте SQL/92 отнесен к набору операторов манипулирования данными (аналог в SQL/89 отсутствует), является оператор объявления временной таблицы. Реальное создание такой таблицы происходит при первом вызове какой-либо процедуры модуля, содержащего объявление. Объявляемая временная таблица видна только процедурам этого модуля. Синтаксис объявления следующий:

<temporary table declaration> ::= DECLARE LOCAL TEMPORARY TABLE <qualified local table name> <table element list> [ ON COMMIT { PRESERVE DELETE } ROWS ] <qualified local table name> ::= MODULE <period> <local table name>

Пояснения:

Объявляемая временная таблица существует в течение SQL-сессии. При завершении сессии такие таблицы уничтожаются путем выполнения неявного оператора DROPTABLE. Ссылки на объявляемую временную таблицу не должны появляться в определениях представлений.


Одиночные операторы манипулирования данными


Каждый из операторов этой группы является абсолютно независимым от какого бы то ни было другого оператора.



Ограничение по ссылкам


Ограничение по ссылкам от заданного набора столбцов CT таблицы T на заданный набор столбцов CT1 некоторой определенной к этому моменту таблицы T1 определяет условие на содержимое обеих этих таблиц, при котором ссылки можно считать корректными.

Если список столбцов CT1 явно специфицирован в определении ограничения по ссылкам, то требуется, чтобы этот список явно входил в какое-либо определение уникальности таблицы T1. Если же список CT1 не специфицирован явно в определении ограничения по ссылкам таблицы T, то требуется, чтобы в определении таблицы T1 присутствовало определение первичного ключа, и список CT1 неявно полагается совпадающим со списком имен столбцов из определения первичного ключа таблицы T1. Имена столбцов списков CT и CT1 должны именовать столбцы таблиц T и T1 соответственно, и не должны появляться в списках более одного раза. Списки столбцов CT и CT1 должны содержать одинаковое число элементов, и столбец таблицы T, идентифицируемый i-ым элементом списка CT должен иметь тот же тип, что столбец таблицы T1, идентифицируемый i-ым элементом списка CT1.

По определению, таблицы T и T1 удовлетворяют заданному ограничению по ссылкам, если для каждой строки s таблицы T такой, что все значения столбцов s, идентифицируемых списком CT, не являются неопределенными, существует строка s1 таблицы T1 такая, что значения столбцов s1, идентифицируемых списком CT1, позиционно равны значениям столбцов s, идентифицируемых списком CT. По человечески это можно сформулировать так: ограничение по ссылкам удовлетворяется, если для каждой корректной ссылки существует объект, на который она ссылается. В привычной программистам терминологии, ограничение по ссылкам не позволяет производить "висячие" ссылки, не ведущие ни к какому объекту.



Ограничение уникальности


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

Действие ограничения уникальности состоит в том, что в таблице T не допускается появление двух или более строк, значения столбцов уникальности которых совпадают.



Оператор чтения очередной строки курсора


Синтаксис оператора чтения следующий:

<fetch statement> ::= FETCH <cursor name> INTO <fetch target list> <fetch target list> ::= <target specification>[{,<target specification>}...]

В операторе чтения указывается имя курсора и обязательный раздел INTO, содержащий список спецификаций назначения (список имен переменных основной программы в случае встроенного SQL или имен "выходных" параметров в случае модуля SQL). Число и типы данных в списке назначений должны совпадать с числом и типами данных списка выборки спецификации курсора.

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

Если таблица, на которую указывает курсор, является пустой, или курсор позиционирован на последнюю строку или за ней, то при выполнении оператора чтения курсор устанавливается в позицию после последней строки, параметру SQLCODE присваивается значение 100, никакие значения не присваиваются целям, идентифицированным в разделе INTO.

Если курсор установлен в позицию перед строкой, то он устанавливается на эту строку, и значения этой строки присваиваются соответствующим целям.

Если курсор установлен на строку r, отличную от последней строки, то курсор устанавливается на строку, непосредственно следующую за строкой r, и значения из этой следующей строки присваиваются соответствующим целям.

Возникает естественный вопрос, каким образом можно параметризовать курсор неопределенным значением или узнать, что выбранное из очередной строки значение является неопределенным. В SQL/89 это достигается за счет использования так называемых индикаторных параметров и переменных. Если известно, что значение, передаваемое из основной программы СУБД или принимаемое основной программой от СУБД, может быть неопределенным, и этот факт интересует прикладного программиста, то спецификация параметра или переменной в операторе SQL имеет вид:

<parametername>[INDICATOR]<parametername> при спецификации параметра, и <embeddedvariablename>[INDICATOR]<embeddedvariablename> при спецификации переменной.

Отрицательное значение индикаторного параметра или индикаторной переменной (они должны быть целого типа) соответствует неопределенному значению параметра или переменной.



Оператор чтения строки по курсору, связанному с динамически подготовленным оператором выборки


<dynamic fetch statement> ::= F ETCH [[<fetch orientation>] FROM] <dynamic cursor name> <using clause>

Пояснения:

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



Оператор фиксации транзакции


Синтаксически оператор фиксации транзакции имеет ту же форму, что и аналогичный оператор в языке SQL/89:

<commit statement> ::= COMMIT [ WORK ]

В дополнение к функциональности оператора COMMITSQL/89 по поводу оператора COMMITSQL/92 следует сделать следующие пояснения:

Для каждой временной таблицы T в каждом модуле, ассоциированном с текущей транзакцией, если для таблицы было указано ONCOMMITDELETE, и эта таблица обновлялась при выполнении текущей транзакции, в течении фиксации транзакции выполняется неявный оператор DELETEFROMT. Проверяются все ранее отложенные ограничения целостности, и если хотя бы одно из них не удовлетворяется, все изменения данных или схемы ликвидируются, и вырабатывается исключительное условие: "откат транзакции по причине нарушения ограничений". Иначе, изменения, произведенные текущей транзакцией над данными и/или схемой становятся доступными другим транзакциям, и текущая транзакция завершается.



Оператор изменения схемы таблицы


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

<alter table statement> ::= ALTER TABLE <table name> <alter table action> <alter table action> ::= <add column definition> |<alter column definition> |<drop column definition> |<add table constraint definition> |<drop table constraint definition>

Пояснения:

Можно изменять схему любой базовой таблицы за исключением объявляемой локальной временной таблицы.

Определение добавления столбца позволяет добавить к таблице новый столбец. Конструкция имеет следующий синтаксис:

<add column definition> ::= ADD [ COLUMN ] <column definition>

Пояснения:

Каждое значение, содержащееся в столбце после его добавления к таблице, есть значение этого столбца по умолчанию. Спецификация определения столбца в операторе ALTERTABLE имеет то же действие, что спецификация определения столбца в определении таблицы. В частности, степень таблицы увеличивается на единицу, и порядковый номер добавляемого столбца устанавливается равным новой степени таблицы.

Определение изменения столбца позволяет установить или отменить значение этого столбца по умолчанию. Конструкция имеет следующий синтаксис:

<alter column definition> ::= ALTER [ COLUMN ] <column name> <alter column action> <alter column action> ::= <set column default clause> |<drop column default clause> <set column default clause> ::= SET <default clause> <drop column default clause> ::= DROP DEFAULT

Пояснения:

В результате выполнения спецификации описатель существующего столбца таблицы изменяется в соответствии с указанным действием. Если указано DROPDEFAULT, соответствующий столбец должен иметь значение по умолчанию.

Определение удаления столбца позволяет ликвидировать указанный столбец таблицы. Конструкция имеет следующий синтаксис:


<drop column definition> ::= DROP [ COLUMN ] <column name> <drop behavior> <drop behavior> ::= CASCADE | RESTRICT

Пояснения:

Если в определении удаления столбца указано RESTRICT, то на удаляемый столбец не должно быть ссылок в выражении запроса любого существующего представления и в условии поиска любого существующего ограничения, кроме табличных ограничений, ссылающихся только на этот столбец и входящих в описание данной таблицы. Если в определении удаления столбца указано CASCADE, то любой зависимый объект уничтожается при выполнении неявного оператора REVOKE (см. ниже). Пусть A обозначает текущий идентификатор авторизации. Пусть T - имя таблицы, для которой выполняется оператор ALTERTABLE, а C - имя удаляемого столбца. Тогда при удалении столбца неявно выполняется следующий оператор от имени текущего системного идентификатора авторизации: REVOKEINSERT(CN), UPDATE(CN), REFERENCES(CN) ONTABLETN FROMACASCADE. Пусть V - имя любого представления, ссылающегося на столбец C таблицы T. При удалении столбца неявно выполняется следующий оператор от имени текущего системного идентификатора авторизации: DROPVIEWVNCASCADE. Идентифицируемый столбец и его описатель уничтожаются. Степень T уменьшается на единицу. Порядковые номера всех столбцов с порядковым номером больше чем у C уменьшаются на единицу.

Определение добавления табличного ограничения имеет следующий синтаксис:

<add table constraint definition> ::= ADD <table constraint definition>

Это определение не нуждается в пояснениях.

Определение уничтожения табличного ограничения имеет следующий синтаксис:

<drop table constraint definition> ::= DROP CONSTRAINT <constraint name> <drop behavior>

Пояснения:

Пусть T имя таблицы, упоминаемой в операторе ALTERTABLE, а TC - имя уничтожаемого ограничения целостности. Если TC является ограничением уникальности и существует ссылочное ограничение RC со ссылкой на таблицу T по столбцам уникальности TC, то будем говорить, что RC зависит от TC. Если указано RESTRICT, то никакое табличное ограничение не должно зависеть от TC. Если указано CASCADE, то все зависимые объекты уничтожаются при выполнении неявного оператора ALTERTABLE (см. ниже). Пусть TCN2 - имя любого табличного ограничения, зависящего от TC, и пусть T2 - имя таблицы, определение которой включало TCN2. Тогда выполняется неявный оператор ALTERTABLET2 DROPCONSTRAINTTCN2 CASCADE. Описатель TC удаляется из описания таблицы T. Идентифицированное табличное ограничение и его описатель разрушаются.


Оператор объявления курсора


Для удобства мы повторим здесь синтаксические правила объявления курсора, приводившиеся раньше:

<declare cursor> ::= DECLARE <cursor name> CURSOR FOR <cursor specification> <cursor specification> ::= <query expression> [<order by clause>...] <query expression> ::= <query term> <query expression> UNION [ALL] <query term> <query term> ::= <query specification> (<query expression>) <order by clause> ::= ORDER BY <sort specification> [{,<sort specification>}...] <sort specification> ::= { <unsigned integer> <column specification> } [ASC DESC]

В объявлении курсора могут задаваться запросы наиболее общего вида с возможностью выполнения операции UNION и сортировкой конечного результата. Этот оператор не является выполняемым, он только связывает имя курсора со спецификацией курсора.



Оператор объявления курсора над динамически подготовленным оператором выборки


<dynamic declare cursor> ::= DECLARE <cursor name> [INSENSITIVE] [SCROLL] CURSOR FOR <statement name>

Пояснения:

Как определяется в стандарте SQL/92, для всех операторов DECLARECURSOR, курсоры фактически создаются при начале транзакции и уничтожаются при ее завершении. Заметим, что в этом операторе <cursorname> и <statementname> - прямо заданные идентификаторы.



Оператор определения курсора над динамически подготовленным оператором выборки


<allocate cursor statement> ::= ALLOCATE <extended cursor name> [INSENSITIVE] [SCROLL] CURSOR FOR <extended statement name> <extended cursor name> ::= (<scope option>] <simple value specification>

Пояснения:

Курсоры, определяемые с помощью оператора ALLOCATECURSOR, фактически создаются при выполнении такого оператора и уничтожаются при выполнении оператора DEALLOCATEPREPARE или при конце транзакции. В этом операторе имена курсора и подготовленного оператора SQL могут задаваться не только в литеральной форме, но и через переменные.

Раздел <scopeoption> относится к области видимости имен: в пределах текущего модуля или в пределах текущей сессии.



Оператор освобождения памяти из-под дескриптора


<deallocate descriptor statement> ::= DEALLOCATE DESCRIPTOR <descriptor name>

Пояснения:

Выполнение этого оператора приводит к освобождению памяти из-под ранее выделенного дескриптора. После этого использование имени дескриптора незаконно в любом операторе, кроме ALLOCATEDESCRIPTOR.



Оператор отката транзакции


Оператор имеет тот же синтаксис и тот же смысл, что и соответствующий оператор SQL/89:

<rollback statement> ::= ROLLBACK [ WORK ]

Дополнительные пояснения не требуются.



Оператор отказа от подготовленного оператора


<deallocate prepared statement> ::= D EALLOCATE PREPARE <SQL statement name>

Пояснения:

Выполнение этого оператора приводит к тому, что ранее подготовленный оператор SQL, связанный с указанным именем оператора, ликвидируется, и соответственно, имя оператора становится неопределенным. Если подготовленный оператор являлся оператором выборки и к моменту выполнения оператора DEALLOCATE существовал открытый курсор, связанный с именем подготовленного оператора, то оператор DEALLOCATE возвращает код ошибки. Если же для подготовленного оператора выборки существовал неоткрытый курсор, образованный с помощью оператора ALLOCATECURSOR, то этот курсор ликвидируется. Если такой курсор объявлялся оператором DECLARECURSOR, то такой курсор переходит в состояние, существовавшее до выполнения оператора PREPARE. Если с курсором был связан подготовленный оператор (динамический DELETE или UPDATE), то для этих операторов выполняется неявный оператор DEALLOCATE.



Оператор отказа от подключения


Оператор DISCONNECT служит для отказа от подключения к SQL-серверу и имеет следующий синтаксис:

<disconnect statement> ::= DISCONNECT <disconnect object> <disconnect object> ::= <connection object> | ALL | CURRENT

Пояснения:

Если специфицировано DEFAULT, и нет текущего или потенциального подключения по умолчанию для текущего SQL-агента, то возбуждается исключительное условие. Если специфицировано CURRENT, и нет текущего подключения для текущего SQL-агента, возбуждается исключительное условие. Пусть C обозначает текущее подключение. Если задано имя подключения, то пусть L обозначает это подключение; если указано CURRENT, то пусть L обозначает текущее подключение; если задано ALL, то пусть L обозначает список всех текущих или потенциальных подключений для данного SQL-агента в порядке, определяемом в реализации; если указано DEFAULT, то пусть L обозначает подключение по умолчанию. Если какое-либо подключение из списка L активно, возбуждается исключительное условие. Для каждого подключения C1 из списка L соответствующая этому подключению сессия S1 рассматривается как текущая сессия, и выполняются все действия, требуемые после последнего вызова процедуры SQL-агентом, за исключением выполнения операторов COMMIT и ROLLBACK. После этого подключение ликвидируется. Если текущее подключение C содержится в списке L, то после выполнения оператора DISCONNECT текущее подключение не существует; в противном случае C остается текущим подключением.



Оператор открытия курсора


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

<open statement> ::= OPEN <cursor name>

В реализациях встроенного SQL обычно требуется, чтобы объявление курсора текстуально предшествовало оператору открытия курсора. Оператор открытия курсора должен быть первым в серии выполняемых операторов, связанных с заданным курсором. При выполнении этого оператора производится подготовка курсора к работе над ним. В частности, в этот момент производится связывание спецификации курсора со значениями переменных основного языка в случае встроенного SQL или параметров в случае модуля.

В большинстве реализаций в случае встроенного SQL именно выполнение оператора открытия курсора приводит к компиляции спецификации курсора.

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



Оператор открытия курсора, связанного с динамически подготовленным оператором выборки


<dynamic open statement> ::= OPEN <dynamic cursor name> [<using clause>]

Пояснения:

По сути, оператор открытия курсора, связанного с динамически подготовленным оператором SQL, отличается от статического случая только возможным наличием раздела using, в котором задаются фактические параметры оператора выборки. Кроме того, имя курсора может задаваться через переменную.



Оператор подготовки


<prepare statement> ::= PREPARE <SQL statement name> FROM <SQL statement variable> <SQL statement variable> ::= <simple target specification> <preparable statement> ::= <preparable SQL data statement> | <preparable SQL schema statement> | <preparable SQL transaction statement> | <preparable SQL session statement> | <preparable implementation-defined statement> <preparable SQL data statement> ::= <delete statement: searched> | <dynamic single row select statement> | <insert statement> | <dynamic select statement> | <update statement: searched> | <preparable dynamic delete statement: positioned> | <preparable dynamic update statement: positioned> <preparable SQL schema statement> ::= <SQL schema statement> <preparable SQL transaction statement> ::= <SQL transaction statement> <preparable SQL session statement> ::= <SQL session statement> <dynamic select statement> ::= <cursor specification> <dynamic simple row select statement> ::= <query specification> <SQL statement name> ::= <statement name> <extended statement name> <extended statement name> ::= [scope option] <simple value specification> <cursor specification> ::= <query expression> [<order by clause>] [<updatability clause>] <updatability clause> ::= FOR { READ ONLY | UPDATE [ OF <column name list> ] } <query expression> ::= <non-join query expression> <joined table> <query specification> ::= SELECT [<set quantifier>] <select list> <table expression> <set quantifier> ::= DISTINCT | ALL

Пояснения:

Оператор PREPARE вызывает компиляцию и построение плана выполнения заданного в текстовой форме оператора SQL. После успешного выполнения оператора PREPARE с подготовленным оператором связывается указанное (литерально или косвенно) имя этого оператора которое потом может быть использовано в операторах DESCRIBE, EXECUTE, OPENCURSOR, ALLOCATECURSOR и DEALLOCATEPREPARE. Эта связь сохраняется до явного выполнения оператора DEALLOCATEPREPARE.



Оператор подготовки с немедленным выполнением


<execute immediate statement> ::= EXECUTE IMMEDIATE <SQL statement variable>

Пояснения:

При выполнении оператора EXECUTEIMMEDIATE производится подготовка и немедленное выполнение заданного в текстовой форме оператора SQL. При этом подготавливаемый оператор не должен быть оператором выборки, не должен содержать формальных параметров и комментариев.



Оператор поискового удаления


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

<delete statement: searched> ::= DELETE FROM <table name> WHERE [<search condition>]

Таблица T, указанная в разделе FROM оператора DELETE, должна быть обновляемой. На вид условия поиска накладывается то ограничение, что на таблицу T не должны содержаться ссылки ни в каком вложенном подзапросе предикатов раздела WHERE.

Фактически оператор выполняется следующим образом: последовательно просматриваются все строки таблицы T, и те строки, для которых результатом вычисления условия выборки является true, удаляются из таблицы T. При отсутствии раздела WHERE удаляются все строки таблицы T.



Оператор поисковой модификации


Оператор обладает следующим синтаксисом:

<update statement: searched> ::= UPDATE <table name> SET <set clause: searched> [{,<set clause: searched>}...] [WHERE <search conditions>] <set clause: searched> ::= <object column: searched> = { <value expression> NULL } <object column: searched> ::= <column name>

Таблица T, указанная в операторе UPDATE, должна быть обновляемой. На условие поиска накладывается то условие, что на таблицу T не должны содержаться ссылки ни в каком вложенном подзапросе предикатов раздела WHERE.

Оператор фактически выполняется следующим образом: таблица T последовательно просматривается, и каждая строка, для которой результатом вычисления условия поиска является true, обновляется в соответствии с разделом SET. Если арифметическое выражение в разделе SET содержит ссылки на столбцы таблицы T, то при вычислении арифметического выражения используются значения столбцов текущей строки до их модификации.



Оператор получения информации из области дескриптора SQL


<get descriptor statement> ::= GET DESCRIPTOR <descriptor name> <get descriptor information> <get descriptor information> ::= <get count> (VALUE <item number> <get item information> ({<comma> <get item information>}...] <get count> ::= <simple target specification 1> <equals operator> COUNT <get item information> ::= <simple target specification 2> <equals operator> <descriptor item name> <item number> ::= <simple value specification> <simple target specification 1> ::= <simple target specification> <simple target specification 2> ::= <simple target specification> <descriptor item name> ::= TYPE (LENGHT (OCTET_LENGHT (RETURNED_LENGHT ( RETURNED_OCTET_LENGHT (PRECISION (SCALE ( DATETIME_INTERVAL_CODE (DATATIME_INTERVAL_PRECISION ( NULLABLE ( INDICATOR (DATA (NAME (UNNAMED (COLLATION_CATALOG ( COLLATION_SCHEMA (COLLATION_NAME (CHARACTER_SET_CATALOG ( CHARACTER_SET_SCHEMA (CHARACTER_SET_NAME <simple target specification> ::= <parameter name> (<embedded variable name>

Пояснения:

Оператор GETDESCRIPTOR служит для выборки описательной информации, ранее размещенной в дескрипторе с помощью оператора DESCRIBE. За одно выполнение оператора можно получить либо число заполненных элементов дескриптора (COUNT), либо информацию, содержащуюся в одном из заполненных элементов.



Оператор позиционного удаления


Синтаксис этого оператора следующий:

<delete statement: positioned> ::= DELETE FROM <table name> WHERE CURRENT OF <cursor name>

Если указанный в операторе курсор открыт и установлен на некоторую строку, и курсор определяет обновляемую таблицу, то текущая строка курсора удаляется, а он позиционируется перед следующей строкой. Таблица, указанная в разделе FROM оператора DELETE, должна быть таблицей, указанной в самом внешнем разделе FROM спецификации курсора.


<dynamic delete statement: positioned> ::= DELETE FROM <table name> WHERE CURRENT OF <dynamic cursor name>

Пояснения:

По сути, оператор позиционного удаления по курсору, связанному с динамически подготовленным оператором SQL, отличается от статического случая только тем, что имя курсора может задаваться через переменную.



Оператор позиционной модификации


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

<update statement: positioned> ::= UPDATE <table name> SET <set clause:positioned> [{,<set clause:positioned>}...] WHERE CURRENT OF <cursor name> <set clause: positioned> ::= <object column:positioned> = { <value expression> NULL } <object column: positioned> ::= <column name>

Если указанный в операторе курсор открыт и установлен на некоторую строку, и курсор определяет обновляемую таблицу, то текущая строка курсора модифицируется в соответствии с разделом SET. Позиция курсора не изменяется. Таблица, указанная в разделе FROМ оператора DELETE, должна быть таблицей, указанной в самом внешнем разделе FROM спецификации курсора.


<dynamic update statement: positioned> ::= UPDATE <table name> SET <set clause> [{<comma> <set clause>}...] WHERE CURRENT OF <dynamic cursor name>

Пояснения:

По сути, оператор позиционной модификации по курсору, связанному с динамически подготовленным оператором SQL, отличается от статического случая только тем, что имя курсора может задаваться через переменную.



Оператор установки дескриптора


<set descriptor statement> ::= SET DESCRIPTOR <descriptor name> <set descriptor information> <set descriptor information> ::= <set count> (VALUE <item number> <set item information> [{<comma> <set item information>}...] <set count> ::= COUNT <equals operator> <simple value specification 1> <set item information> ::= <descriptor item name> <equals operator> <simple value specification 2> <simple target specification 1> ::= <simple target specification> <simple target specification 2> ::=<simple target specification> <item number> ::= <simple value specification>

Пояснения:

Оператор SETDESCRIPTOR служит для заполнения элементов дескриптора с целью его использования в разделе USING. За одно выполнение оператора можно поместить значение в поле COUNT (число заполненных элементов), либо частично или полностью сформировать один элемент дескриптора.



Оператор установки идентификатора авторизации сессии


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

<set session authorization identifier statement> ::= SET SESSION AUTHORIZATION <value specification>

Пояснения:

Спецификация значения должна иметь тип символьных строк. В реализации определяется, можно ли явно менять идентификатор авторизации сессии. Если это допускается в реализации, идентификатор авторизации сессии устанавливается в заданное значение.



Оператор установки имени набора символов по умолчанию


Оператор позволяет установить имя набора символов по умолчанию для применения в идентификаторах и строчных литеральных константах, используемых в динамических операторах, подготавливаемых с помощью оператора немедленного выполнения, оператора подготовки, или в прямых операторах SQL. Оператор определяется следующим синтаксическим правилом:

<set names statement> ::= SET NAMES <value specification>

Пояснения:

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



Оператор установки имени схемы по умолчанию


Оператор позволяет установить имя схемы по умолчанию для расширения неквалифицированных имен, используемых в динамических операторах, подготавливаемых с помощью оператора немедленного выполнения, оператора подготовки, или в прямых операторах SQL. Оператор определяется следующим синтаксическим правилом:

<set schema statement> ::= SET SCHEMA <value specification>

Пояснения:

Спецификация значения должна иметь тип символьных строк. Пусть V обозначает символьную строку, задающую спецификацию схемы по умолчанию. Если V содержит имя каталога, то пусть X обозначает часть V, соответствующую имени каталога, а Y - часть V, соответствующую неквалифицированному имени схемы. Тогда неявно выполняется следующий оператор: SETCATALOG 'X', а оператор установки имени схемы по умолчанию заменяется на SETSCHEMA 'Y'. В противном случае, V дополняется неквалифицированным именем схемы текущей SQL-сессии.



Оператор установки режима ограничений


При выполнении в активной транзакции оператор устанавливает режим проверки ограничений целостности для этой транзакции в текущей SQL-сессии. При выполнении вне активной транзакции оператор устанавливает режим проверки ограничений целостности для следующей транзакции данного агента в текущей сессии. Оператор имеет следующий синтаксис:

<set constraints mode statement> ::= SET CONSTRAINTS <constraint name list> { DEFERRED | IMMEDIATE } <constraint name list> ::= ALL | <constraint name> [ { <comma> <constraint name> }... ]

Пояснения:

Указанные в параметрах оператора ограничения должны быть откладываемыми. Пусть TXN обозначает текущую или следующую транзакцию данного агента в зависимости от того, в транзакции или вне транзакции выполняется оператор. Если в операторе SETCONSTRAINTS указано IMMEDIATE, то

(a) если специфицировано ALL, то для всех откладываемых ограничений TXN устанавливается режим немедленной проверки;

(b) в противном случае режим немедленной проверки устанавливается для всех ограничений, поименованных в списке имен ограничений.

Если указано DEFERRED, то

(a) если специфицировано ALL, то для всех откладываемых ограничений TXN устанавливается режим отложенной проверки;

(b) в противном случае режим отложенной проверки устанавливается для всех ограничений, поименованных в списке имен ограничений.



Оператор вставки


Оператор служит для создания новых строк в таблице и обладает следующим синтаксисом:

<insert statement> ::= INSERT INTO <table name> [(<insert column list>)] {VALUES (<insert value list>) <query specification>} <insert column list> ::= <column name> [{,<column name>}...] <insert value list> ::= <insert value> [{,<insert value>...] <insert value> ::= <value specification> NULL

Таблица T, указанная в операторе INSERT, должна быть обновляемой и не должна указываться в разделе FROM спецификации запроса или подзапроса, используемого в разделе VALUES.

Выполнение оператора INSERT происходит следующим образом: создается возможная (candidate) строка, содержащая столько же столбцов, сколько их в таблице T (если T - представление, то возможная строка содержит столько столбцов, сколько их в таблице, порождающей T); для каждого объектного столбца возможной строки его значение заменяется на вставляемое значение; полученная строка заносится в T.

Если в разделе VALUES указывается спецификация запроса, то пусть R обозначает ее результат. Если R пуст, то параметру SQLCODE присваивается значение 100, и никакая строка не вставляется. Число созданных возможных строк равно мощности R. Вставляемые значения одной возможной строки являются значениями одной строки R, и значения в одной строке R являются вставляемыми значениями одной возможной строки.



Оператор выбора подключения


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

<set connection statement> ::= SET CONNECTION <connection object> <connection object> ::= DEFAULT |<connection name>

Пояснения:

Если оператор выбора подключения выполняется после первого оператора SQL, инициировавшего выполнение текущей транзакции, и реализация не поддерживает транзакции, взаимодействующие более чем с одним SQL-сервером, то возбуждается исключительное условие. Если специфицировано DEFAULT, и отсутствует текущее или потенциальное подключение по умолчанию для текущего SQL-агента, то возбуждается исключительное условие. В противном случае должно существовать текущее или потенциальное подключение с указанным именем; при неверном указании имени возбуждается исключительное условие. Текущие подключение и сессия становятся потенциальными; информация о контексте сервера сохраняется и не влияет на выполнение операций через выбранное подключение. Выбранное подключение и соответствующая SQL-сессия становятся текущими; информация о контексте сессии восстанавливается к тому состоянию, в котором она находилась к моменту перехода в потенциальную.



Оператор выборки


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

Замечание: В диалекте SQL СУБД Oracle поддерживается расширенный вариант оператора выборки, результатом которого не обязательно является таблица из одной строки. Такое расширение не поддерживается ни в SQL/89, ни в SQL/92.


Для удобства мы повторяем синтаксис этого оператора еще раз:

<select statement> ::= SELECT [ALL DISTINCT] <select name> INTO <select target list> <table expression> <select target list>::= <target specification> [{,<target specification>}...]

Поскольку, как мы уже объясняли, результатом одиночного оператора выборки является таблица, состоящая не более, чем из одной строки, список целей специфицируется в самом операторе.



Оператор выполнения подготовленного оператора


<execute statement> ::= EXECUTE <SQL statement name> (<result using clause>] (<parameter using clause>] <result using clause> ::= <using clause> <parameter using clause> ::= <using clause>

Пояснения:

Оператор EXECUTE может быть применен к любому ранее подготовленному оператору SQL, кроме <dynamicselectstatement>. Если это оператор <dynamicsinglerowselectstatement>, то оператор EXECUTE должен содержать раздел <resultusingclass> с ключевым словом INTO. В любом случае число фактических параметров, задаваемых через разделы using, должно соответствовать числу формальных параметров, определенных в подготовленном операторе SQL.



Оператор закрытия курсора


Синтаксис этого оператора следующий:

<close statement> ::= CLOSE <cursor name>

Если к моменту выполнения этого оператора курсор находился в открытом состоянии, то оператор переводит курсор в закрытое состояние. После этого над курсором возможно выполнение только оператора OPEN.