Классика баз данных - статьи

         

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


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

<allocate descriptor statement> ::=ALLOCATE DESCRIPTOR <descriptor name>[WITH MAX <occurrences>]<occurences> ::= <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, описание которых может потребоваться. С этим же связано то, что имя дескриптора может задаваться как литеральной строкой символов, так и через строковую переменную включающего языка, т. е. его можно генерировать во время выполнения программы.

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



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


Синтаксис оператора:

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

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



Оператор получения информации из области дескриптора 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</PRE>| COLLATION_SCHEMA| COLLATION_NAME| CHARACTER_SET_CATALOG| CHARACTER_SET_SCHEMA| CHARACTER_SET_NAME<simple target specification> ::=<parameter name>| <embedded variable name>

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



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


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

<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>

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



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




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

<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, OPEN CURSOR, ALLOCATE CURSOR и DEALLOCATEPREPARE. Эта связь сохраняется до явного выполнения оператора DEALLOCATEPREPARE.



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


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

<deallocate prepared statement> ::=DEALLOCATE PREPARE < SQL statement name>

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



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


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

<describe statement> ::=<describe input statement>| <describe output statement><describe input statement> ::=DESCRIBE INPUT < SQL statement name><using descriptor><describe output statement> ::=DESCRIBE [OUTPUT] < SQL statement name><using descriptor><using clause> ::=<using arguments>| <using descriptor><using arguments> ::={ USING | INTO }<argument> [{<comma> <argument>}. . . ]<argument> ::= <target specification><using descriptor> ::={ USING | INTO } SQL DESCRIPTOR <descriptor name><target specification> ::=<parameter specification>| <variable specification><parameter specification> ::=<parameter name> [<indicator parameter>]<indicator parameter> ::=[INDICATOR] <parameter name><variable specification> ::=<embedded variable name> [<indicator variable>]<indicator variable> ::=[INDICATOR] <embedded variable name>

При выполнении оператора DESCRIBE происходит заполнение указанного в операторе дескриптора информацией, описывающей либо результат ранее подготовленного оператора SQL (если это оператор выборки), либо количество и типы параметров подготовленного оператора. В <using descriptor> полагается писать USING SQL DESCRIPTOR.



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


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

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

Оператор EXECUTE может быть применен к любому ранее подготовленному оператору SQL, кроме <dynamic select statement>. Если это оператор <dynamic single row select statement>, то оператор EXECUTE должен содержать раздел <result using class> с ключевым словом INTO. В любом случае число фактических параметров, задаваемых через разделы using, должно соответствовать числу формальных параметров, определенных в подготовленном операторе SQL.



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


Синтаксис оператора:

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

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



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


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

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

как определяется в новом стандарте, для всех операторов DECLARE CURSOR курсоры фактически создаются при начале транзакции и уничтожаются при ее завершении. Заметим, что в этом операторе <cursor name> и <statementname> прямо (литерально) заданные идентификаторы.



Другая разновидность оператора


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

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

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

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



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


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

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

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



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


Синтаксис:

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

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



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


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

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

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



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


Синтаксис:

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

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



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


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

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

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



Подготавливаемый оператор позиционного удаления


Синтаксис оператора:

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

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



Подготавливаемый оператор позиционной модификации


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

См. .

Если внимательно сравнить средства динамического SQL СУБД Oracle V. 6и стандарта SQL/92, то видно, что Oracle практически вкладывается в стандарт, если не считать небольших синтаксических различий и (что существенно более важно) разного стиля работы с дескрипторами. Думается, что примерно такая же ситуация имеет место в других СУБД, поддерживающих динамический SQL.

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

ограничиться подмножеством операторов динамического SQL, реализованным в Oracle V. 6; локализовать части программы, связанные с работой с дескрипторами (т. е. как минимум не допускать прямой работы с полями области дескрипторов в стиле Oracle).



существенно шире того, который


Набор операторов динамического SQL в стандарте SQL/ 92 существенно шире того, который был реализован в Oracle V. 6. В основном это связано с тем, что введены операторы для работы с дескрипторами, а также появились подготавливаемые операторы позиционного удаления и позиционной модификации.


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


Оператор PREPARE имеет синтаксис:

<prepare-statement> ::=PREPARE <statement-name> FROM <host-string-variable><statement-name> ::= <name>

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

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



РАЗДЕЛ FROM


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

"расширенное произведение R есть мультимножество всех строк r, таких, что r является конкатенацией строк из всех идентифицированных таблиц в том порядке, в котором они идентифицированы. Мощность R есть произведение мощностей идентифицированных таблиц. Порядковый номер столбца в R есть n+s, где n - порядковый номер порождающего столбца в именованной таблице T, а s - сумма степеней всех таблиц, идентифицированных до T в разделе FROM". (Возможно, читатель не испытает особого восторга от приведенного абзаца, но таков стиль стандарта.)

Как видно из синтаксиса, рядом с именем таблицы можно указывать еще одно имя "correlation name". Фактически, это некоторый синоним имени таблицы, который можно использовать в других разделах табличного выражения для ссылки на строки именно этого вхождения таблицы. (Одна и та же таблица может участвовать несколько раз в списке одного раздела FROM и/или входить в списки разделов FROM нескольких (под)запросов.)

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



СПЕЦИФИКАЦИЯ ЗАПРОСА


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



Типы данных


Набор встроенных типов данных предполагается расширить типами BOOLEAN и ENUMERATED. Хотя по причине поддержки неопределенных значений языку SQL свойственно применение трехзначной логики, тип BOOLEAN содержит только два возможных значения true и false. Для представления значения unknown рекомендуется использовать NULL, что, конечно, не вполне естественно. Перечисляемый тип ENUMERATED обладает свойствами, подобными свойствам перечисляемых типов в языках программирования.

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

Предполагается включение в язык возможности использовать определенные пользователями типы данных. Видимо, будут иметься возможности определения абстрактных типов данных с произвольно сложной внутренней структурой на основе таких традиционных спецификаций агрегирования и структуризации, как LIST, ARRAY, SET, MULTISET и TURPLE, а также возможности определения объектных типов с соответствующими методами в стиле объектно-ориентированного подхода.

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



ТИПЫ ДАННЫХ


Появилась возможность использования типа данных символьных строк переменной длины (т. е. при спецификации столбца указывается предельно допустимый размер хранимой строки в символах, а реально в базе данных хранится ровно столько символов, сколько их ввел пользователь). Введены типы данных битовых строк постоянной и переменной длины ( как они реально хранятся в базе данных, в стандарте не определяется). Наконец, стандартизованы темпоральные типы данных DATE (дата), TIME (время) и INTERVAL (временной интервал).



ИНТЕРНАЦИОНАЛИЗАЦИЯ И НАЦИОНАЛИЗАЦИЯ


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



ОПРЕДЕЛЕНИЕ СХЕМЫ БД И МАНИПУЛИРОВАНИЕ СХЕМОЙ БД


Наконец-то появилась возможность создавать хранимые и представляемые таблицы и задавать или удалять привилегии доступа (операторы CREATE TABLE, CREATE VIEW, GRANT, REVOKE) в любой момент времени в любой транзакции вне оператора определения схемы. Появились операторы уничтожения таблиц (DROPTABLE и DROP VIEW), которые также можно выполнять внутри любой транзакции(при наличии соответствующих привилегий). Вообще, следует заметить, что в стандарте SQL/92 для любого оператора класса CREATE существует парный оператор класса DROP. Специфицирован также оператор ALTER TABLE, позволяющий динамически изменять характеристики ранее созданной таблицы (в частности добавлять к ней новые столбцы). Все упомянутые здесь операторы могут включаться в модуль SQL.



ОГРАНИЧЕНИЯ ЦЕЛОСНОСТИ


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

Появилась возможность определения отложенных (проверяемых при завершении транзакции) ограничений целостности.

Расширены возможности определения ограничений внешнего ключа (ограничений ссылочной целостности).

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



ПРЕДСТАВЛЕНИЯ


В стандарте SQL/92 осмысленно ослаблены требования к изменяемым представлениям(в условии выборки допускаются подзапросы, не коррелирующие со столбцами таблицы разделы FROM основного запроса). Заметим, что множество изменяемых запросов SQL/92 по-прежнему не включает все представления, которые теоретически являются изменяемыми.

Уточнен смысл конструкции WITH CHECK OPTION: введены ключевые слова LOCAL и CASCADE. При указании LOCAL контролируется, что измененная строка останется видимой в том представлении, для которого выполнялся оператор UPDATE. Если же указывается CASCADE, то изменение должно остаться видимым в данном представлении и во всех представлениях, которые определены над исходным представлением (на самом деле мы несколько упрощаем ситуацию, для полного анализа которой требуется длительное рассмотрение комбинаций наличия и отсутствия конструкции WITH CHECK OPTION у исходного представления и того, которое над ним определено).



ТАБЛИЧНЫЕ ВЫРАЖЕНИЯ


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

Появился новый класс табличных выражений, называемых "табличными выражениями с соединениями " (join-table-expression), которые можно использовать только в разделе FROM. Такие табличные выражения строятся на основе базовых и/или представляемых таблиц на основе использования разных видов операции соединения: CROSS JOIN (Декартово произведение), INNER (обычное соединение), LEFT и LEFT OUTER (левое и левое внешнее соединение), RIGHT и RIGHT OUTER (правое и правое внешнее соединение), FULL и FULL JOIN (полное и полное внешнее соединение) и UNION (объединение). (Не уверен, что от появления этого класса табличных выражений потенциальным пользователям реализаций SQL/92 станет жить легче, хотя возможно станет легче формулировать запросы людям, привыкшим к алгебраическому стилю работы с базами данных. )



ВЫРАЖЕНИЯ ЗАПРОСОВ


При построении выражений запросов (формально, согласно синтаксису SQL/92, соответствующие конструкции не называются выражениями запросов; тем не менее мы предпочитаем сохранить этот термин для сближения с семантикой SQL/89), кроме операции теоретико-множественного объединения UNION, которая присутствовала в SQL/89, стало возможным использовать операции EXCEPT (теоретико-множественное вычитание) и INTERSECT (теоретико-множественное пересечение). Заметим для точности, что возможность получения в качестве результата запроса мультимножества строк (т. е. с дубликатами) не позволяет однозначно интерпретировать сразу все эти операции. Поэтому результат одного и того же выражения запросов в разных реализациях может быть разным.



КУРСОРЫ


При определении курсора можно указывать ключевые слова SCROLL и INSENSITIVE. Указание SCROLL означает, что курсор можно явно позиционировать: на первую строку результирующего множества запроса, на последнюю строку, на строку с позицией с положительным или отрицательным смещением от текущей строки, на строку с явно указанным абсолютным номером позиции. Наличие ключевого слова INSENSITIVE означает, что какие бы изменения в базовых таблицах не производились в той же транзакции, в которой определен курсор, они не должны влиять на результирующее множество строк курсора после его открытия. Заметим, что, хотя внешне эти возможности выглядят очень привлекательно, их реализация стоит недешево. И в том и в другом случае требуется явное и почти всегда полное построение результирующего множества запроса, связанного с курсором.



УПРАВЛЕНИЕ ТРАНЗАКЦИЯМИ И УРОВНИ ИЗОЛЯЦИИ


Известно, что в большинстве SQL-ориентированных реляционных СУБД поддерживаются несколько режимов изолированности транзакций. В стандарте SQL/92 специфицирован оператор SET TRANSACTION, который, в частности, позволяет явно установить один из следующих режимов, влияющих на уровень изолированности транзакции: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE.

В соответствии со стандартом режим READ UNCOMMITTED допускает наличие чтения "грязных данных " (если транзакция T1 работает в этом режиме, то она может прочитать данные, обновленные транзакцией T2, которая заканчивается откатом; эти данные "грязные ", поскольку никогда не будут существовать в БД).

При установке режима READ COMMITTED транзакция не сможет прочитать "грязные данные ", но в ней может возникнуть ситуация "неповторяющегося чтения " (пусть транзакция T1 работает в этом режиме и в ней выполняется выборка некоторой строки некоторой таблицы; после этого в транзакции T2срабатывает оператор, обновляющий эту строку; теперь в транзакции T1 снова выполняется оператор, выбирающий ту же строку, и прикладная программа или интерактивный пользователь с удивлением обнаруживают, что значения полей строки изменились).

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

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

Кроме указания режима изоляции в операторе SET TRANSACTION можно указать, является ли транзакция только читающей базу данных (READ ONLY) или обновляющей(READ WRITE). По умолчанию любая транзакция считается обновляющей, если только не задан режим изоляции READ UNCOMMITTED. В последнем случае транзакция полагается только читающей. Другими словами, комбинация READ WRITE и READUNCOMMITTED является недопустимой.



ДИНАМИЧЕСКИЙ SQL


В стандарте определены операторы динамического SQL. См. разд. .



ВСТРОЕННЫЙ SQL


как отмечалось в разд. 2. 5, стандарт SQL/89 формально не включал раздел, посвященный встраиванию конструкций SQL в программу на традиционном языке программирования. Этот раздел являлся приложением и, кроме того, не включал правил встраивания для языков Си и Ада. В SQL/92 полностью специфицированы правила встраивания для наиболее распространенных языков программирования(Ада, Си, Кобол, Фортран, MUMPS, Паскаль, ПЛ/1).



ИНТЕРАКТИВНЫЙ (ПРЯМОЙ) SQL


В SQL/92 специфицирован набор операторов SQL, которые должны поддерживаться в интерактивном режиме, хотя некоторые решения по-прежнему отдаются на откуп реализациям.

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



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


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

<comparison predicate> ::=<value expression> <comp op>{<value expression> | <subquery>}<comp op> ::== | <> | < | > | <= | >=

Через "<>" обозначается операция "неравенства". Арифметические выражения левой и правой частей предиката сравнения строятся по общим правилам построения арифметических выражений и могут включать в общем случае имена столбцов таблиц из раздела FROM и константы (не обязательно литеральные; вместо литеральной константы может использоваться имя столбца таблицы, указанной в разделе FROM более внешнего подзапроса, или имя переменной программы, написанной на объемлющем языке). Типы данных арифметических выражений должны быть сравнимыми (например, если тип столбца a таблицы A является типом символьных строк, то предикат "a = 5" недопустим).

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

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



Расширения языка


В языке, определяемом стандартом SQL/92, содержится много свойств, которые отсутствовали в языке SQL/89. Ниже приводится краткая сводка этих свойств.



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


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



Предикат between


Предикат between имеет следующий синтаксис:

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

По определению результат "x BETWEEN y AND z" тот же самый, что результат логического выражения "x >= y AND x <= z". Результат "x NOT BETWEEN y AND z" тот же самый, что результат "NOT (x BETWEEN y AND z)".



Предикат in


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

<in predicate> ::=<value expression> [NOT] IN{<subquery> | (<in value list>)}<in value list> ::=<value specification>{,<value specification>}...

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

Значение предиката равно true в том и только в том случае, когда значение левого операнда совпадает хотя бы с одним значением списка правого операнда. Если список правого операнда пуст (так может быть, если правый операнд задается подзапросом) или значение "подразумеваемого" предиката сравнения x = y (где x - значение арифметического выражения левого операнда)равно false для каждого элемента y списка правого операнда, то значение предиката in равно false. В противном случае значение предиката in равно unknown (например, так может быть, если значение левого операнда есть NULL).По определению значение предиката "x NOT IN S" равно значению предиката "NOT (x IN S)".



Предикат like


Предикат like имеет следующий синтаксис:

<like predicate> ::=<column specification> [NOT] LIKE <pattern>[ESCAPE <escape character>]<pattern> ::= <value specification><escape character> ::= <value specification>

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

Значение предиката равно true, если pattern является подстрокой заданного столбца. При этом если раздел ESCAPE отсутствует, то при сопоставлении шаблона со строкой производится специальная интерпретация двух символов шаблона: символ подчеркивания ("_") обозначает любой одиночный символ; символ процента ("%") обозначает последовательность произвольных символов произвольной длины (может быть, нулевой).

Если же раздел ESCAPE присутствует и специфицирует некоторый одиночный символ x, то пары символов "x_" и "x%" представляют одиночные символы "_" и "%", соответственно.

Значение предиката like есть unknown, если значение столбца либо шаблона не определено.

Значение предиката "x NOT LIKE y ESCAPE z" совпадает со значением "NOT x LIKE y ESCAPE z".



Предикат null


Предикат null описывается синтаксическим правилом

<null predicate> ::=<column specification> IS [NOT] NULL

Этот предикат всегда принимает значения true или false. При этом значение "x IS NULL" равно true тогда и только тогда, когда значение х не определено. Значение предиката "x NOT IS NULL" равно значению "NOT x IS NULL".



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


Предикат с квантором имеет следующий синтаксис:

<quantified predicate> ::=<value expression><comp op> <quantifier> <subquery><quantifier> ::=<all> | <some><all> ::= ALL<some> ::= SOME | ANY

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

Предикат "x <comp op> ALL S" имеет значение true, если S пусто или значение предиката "x <comp op> s" равно true для каждого s, входящего в S. Предикат "x <comp op> ALL S" имеет значение false, если значение предиката "x <comp op> s" равно false хотя бы для одного s, входящего в S. В остальных случаях значение предиката "x <comp op> ALL S" равно unknown.

Предикат "x <comp op> SOME S" имеет значение false, если S пусто или значение предиката "x <comp op> s" равно false для каждого s, входящего в S. Предикат "x <comp op> SOMES" имеет значение true, если значение предиката "x <comp op>s" равно true хотя бы для одного s, входящего в S. В остальных случаях значение предиката "x <comp op> SOME S" равно unknown.



Предикат exists


Предикат exists имеет следующий синтаксис:

< exists predicate> ::=EXISTS <subquery>

Значением этого предиката всегда является true или false, и это значение равно true тогда и только тогда, когда результат вычисления подзапроса не пуст.



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


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

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

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

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


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


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

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



РАЗДЕЛ WHERE


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

<where clause> ::=WHERE <search condition><search condition> ::=<boolean term>| <search condition> OR <boolean term><boolean term> ::=<boolean factor>| <boolean term> AND <boolean factor><boolean factor> ::=[NOT] <boolean primary><boolean primary> ::=<predicate> | (<search condition>)

Вычисление раздела WHERE производится по следующим правилам: пусть R- результат вычисления раздела FROM. Тогда условие поиска (search condition)применяется ко всем строкам R, и результатом раздела WHERE является таблица, состоящая из тех строк R, для которого результатом вычисления условия поиска является true. Если условие выборки включает подзапросы, то каждый подзапрос вычисляется для каждого кортежа таблицы R (в стандарте используется термин "effectively" в том смысле, что результат должен быть таким, как если бы каждый подзапрос действительно вычислялся заново для каждого кортежа R, хотя реально это требуется далеко не всегда).

Заметим, что поскольку SQL/89 допускает наличие в базе данных неопределенных значений, то вычисление условия поиска должно производиться не в булевой, а в трехзначной логике со значениями true, false и unknown (неизвестно).Для любого предиката известно, в каких ситуациях он может порождать значение unknown. Булевские операции AND, OR и NOT работают в трехзначной логике следующим образом:

true AND unknown = unknownunknown AND true = unknownunknown AND unknown = unknowntrue OR unknown = trueunknown OR true = trueunknown OR unknown = unknownNOT unknown = unknown

Среди предикатов условия поиска в соответствии с SQL/89 могут находиться следующие предикаты: предикат сравнения, предикат between, предикат in, предикат like, предикат null, предикат с квантором и предикат exists. Сразу заметим, что во всех реализациях SQL на эффективность выполнения запроса существенно влияет наличие в условии поиска простых предикатов сравнения(предикатов, задающих сравнение столбца таблицы с константой). Наличие таких предикатов позволяет СУБД использовать индексы при выполнении запроса, т.е. избегать полного просмотра таблицы. Хотя в принципе язык SQL дает возможность пользователям не заботиться о конкретном наборе предикатов в условии выборки (лишь бы они были синтаксически и семантически правильны),при реальном использовании SQL-ориентированных СУБД такие технические детали стоит иметь в виду.



В этом разделе содержится краткая


В этом разделе содержится краткая сводка различий между SQL/92 и SQL/89. Синтаксические и семантические детали конструкций SQL/92 не приводятся. Еще раз подчеркнем, что в изложении мы следуем книге Дейта "Стандарт SQL ".


ВЫРАЖЕНИЕ ЗАПРОСОВ


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



СЕМАНТИКА АГРЕГАТНЫХ ФУНКЦИЙ


Агрегатные функции предназначены для того, чтобы вычислять некоторое значение для заданного множества строк. Таким множеством строк может быть группа строк, если агрегатная функция применяется к сгруппированной таблице, или вся таблица. Для всех агрегатных функций, кроме COUNT(*), фактический(т. е. требуемый семантикой) порядок вычислений следующий: на основании параметров агрегатной функции из заданного множества строк производится список значений. Затем по этому списку значений производится вычисление функции. Если список оказался пустым, то значение функции COUNT для него есть 0, а значение всех остальных функций null.

Пусть T обозначает тип значений из этого списка. Тогда результат вычисления функции COUNT - точное число с масштабом и точностью, определяемыми в реализации. Тип результата значений функций MAX и MIN совпадает с T. При вычислении функций SUM и AVG тип T не должен быть типом символьных строк, а тип результата функции - это тип точных чисел с определяемыми в реализации масштабом и точностью, если T - тип точных чисел и тип приблизительных чисел с определяемой в реализации точностью, если T - тип приблизительных чисел.

Вычисление функции COUNT(*) производится путем подсчета числа строк в заданном множестве. Все строки считаются различными, даже если они состоят из одного столбца со значением null во всех строках.

Если агрегатная функция специфицирована с ключевым словом DISTINCT, то список значений строится из значений указанного столбца. (Подчеркнем, что в этом случае не допускается вычисление арифметических выражений!)Далее из этого списка удаляются неопределенные значения, и в нем устраняются значения-дубликаты. Затем вычисляется указанная функция.

Если агрегатная функция специфицирована без ключевого слова DISTINCT(или с ключевым словом ALL), то список значений формируется из значений арифметического выражения, вычисляемого для каждой строки заданного множества. Далее из списка удаляются неопределенные значения, и производится вычисление агрегатной функции. Обратите внимание, что в этом случае не допускается применение функции COUNT!

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



РЕЗУЛЬТАТЫ ЗАПРОСОВ


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

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

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

Аналогично обстоит дело в том случае, когда R представляет собой сгруппированную таблицу, но табличное выражение не содержит раздела GROUP BY (и, следовательно, содержит раздел HAVING). Если в предыдущем случае существовало два варианта формирования списка выборки: только с прямым указанием столбцов R или только с указанием их внутри спецификаций агрегатных функций, то в данном случае возможен только второй вариант. Результат табличного выражения явно объявлен сгруппированной таблицей, состоящей из одной группы, и результат запроса можно формировать только путем применения агрегатных функций к этой группе строк. Опять результатом запроса является таблица, состоящая не более чем из одной строки, полученной путем применения агрегатных функций к R.

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



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


Агрегатные функции (в стандарте 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 -среднее значение.