Стандарты языка реляционных баз данных SQL: краткий обзор

С.Д.Кузнецов
1. Введение
2. Язык баз данных SQL/89
2.1 Структура стандарта и его характеристика
2.2 Типы данных
2.3 Структура запросов
2.4 Средства определения схемы
2.5 Язык модулей или встроенный SQL?
2.6 Набор операторов манипулирования данными
3. Динамический SQL в Oracle V.6
3.1 Оператор подготовки
3.2 Оператор получения описания подготовленного оператора
3.3 Оператор выполнения
3.4 Работа с динамическими операторами SQL через курсоры
4. Некоторые черты SQL/92
4.1 Динамический SQL в стандарте SQL/92
4.2 Сводка отличий SQL/92 от SQL/89
5. Сводка возможностей SQL-3
5.1 Типы данных
5.2 Некоторые другие свойства SQL-3
6. Заключение

1. Введение

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

Под мобильностью прикладной системы мы понимаем не только возможность ее простого переноса на другую аппаратную платформу, но и возможность сравнительно легкого приспособления к использованию другой СУБД. Мы не рассматриваем в этом документе проблемы переносимости, связанные с особенностями операционных систем. Заметим, что в общем случае проблемы переноса будут существенно проще, если целевыми аппаратными средствами являются UNIX-компьютеры, причем в качестве операционной системы используются современные версии ОС UNIX, соответствующие международным стандартам (например системы семейства System V Release 4.x), а в качестве языка программирования используется хорошо стандартизованный язык (далее мы предполагаем использование языка ANSI Си). Конечно, при некоторых дополнительных ограничениях на программирование(если это позволяет специфика прикладной системы) иногда можно добиться возможности несложного переноса прикладной системы в среду другой операционной системы.

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

К сожалению, на практике дела обстоят не совсем так, и в разных СУБД, производители которых объявляют их соответствующими стандарту SQL, достаточно часто реализуются немного разные языки. Частично это объясняется недостатками самого стандарта, частично - историческими и конъюнктурными обстоятельствами. К сожалению, такова текущая реальность, и к ней нужно приспосабливаться.

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

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

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

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

2. Язык баз данных SQL/89

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

2.1 Структура стандарта и его характеристика

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

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

Пятая глава ("Общие элементы") содержит формальные определения(описание синтаксиса и семантики) элементов языка. К наиболее важным разделам этой главы относятся определения типов данных языка SQL/89; предикатов, которые допускается использовать в условиях выборки; общей структуры запросов.

Шестая глава ("Язык определения схем") посвящается средствам определения схемы БД в SQL/89.

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

Восьмая глава ("Язык манипулирования данными") содержит формальное описание синтаксиса и семантики наиболее важной для прикладного программирования части языка SQL - набора операторов непосредственного манипулирования хранимыми в БД данными.

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

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

Если характеризовать текст стандарта с точки зрения практически заинтересованного читателя, нужно заметить, что читать его (даже в переводе на русский язык)- это трудная и неприятная задача. Стремление добиться точных и недвусмысленных формулировок часто приводит к появлению совершенно неудобочитаемых предложений. Из имеющихся более просто читаемых толкований стандарта SQL/89 следует отметить одно из первых изданий книги Дейта "Стандарт SQL" (в последнем издании описан стандарт SQL/92). Лучшим способом изучения стандарта было бы чтение этой книги с параллельным заглядыванием в текст стандарта по мере необходимости. К сожалению, на русском языке эти книги не изданы(и, насколько мне известно, даже не переведены).

2.2 Типы данных

В языке SQL/89 поддерживаются следующие типы данных: CHARACTER, NUMERIC,DECIMAL, INTEGER, SMALLINT, FLOAT, REAL, DOUBLE PRECISION. Эти типы данных классифицируются на типы строк символов, точных чисел и приблизительных чисел.

К первому классу относится тип CHARACTER. Спецификатор типа имеет вид CHARACTER (length), где length задает длину строк данного типа. Заметим, что в SQL/89 нет типа строк переменного размера, хотя во многих реализациях они допускаются. Литеральные строки символов изображаются в виде "последовательность-символов"(например "example").

Представителями второго класса типов являются NUMERIC, DECIMAL (или DEC), INTEGER (или INT) и SMALLINT. Спецификатор типа NUMERIC имеет вид NUMERIC [(precision [, scale])]. Специфицируются точные числа, представляемые с точностью precision и масштабом scale. Здесь и далее, если опущен масштаб, то он полагается равным 0, а если опущена точность, то ее значение по умолчанию определяется в реализации.

Спецификатор типа DECIMAL (или DEC) имеет вид DECIMAL [(precision [,scale])]. Специфицируются точные числа, представленные с масштабом scale и точностью, равной или большей значения precision.

INTEGER специфицирует тип данных точных чисел с масштабом 0 и определяемой в реализации точностью. SMALLINT специфицирует тип данных точных чисел с масштабом 0 и определяемой в реализации точностью, не большей, чем точность чисел типа INTEGER.

Литеральные значения точных чисел в общем случае представляются в форме[+|-] <целое-без-знака> [.<целое-без-знака>].

Наконец, в классу типов данных приблизительных чисел относятся типы FLOAT, REAL и DOUBLE PRECISION. Спецификатор типа FLOAT имеет вид FLOAT[(precision)]. Специфицируются приблизительные числа с двоичной точностью, равной или большей значения precision.

REAL специфицирует тип данных приблизительных чисел с точностью, определенной в реализации. DOUBLE PRECISION специфицирует тип данных приблизительных чисел с точностью, определенной в реализации и большей, чем точность типа REAL.

Литеральные значения приблизительных чисел в общем случае представляются в виде <литеральное-значение-точного-числа>E<целое-со-знаком>.

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

Хотя правила встраивания SQL в программы на языке Си не определены в SQL/89, в большинстве реализаций, поддерживающих такое встраивание, имеется следующее соответствие между типами данных SQL и типами данных Си: CHARACTER соответствует строкам Си; INTEGER соответствует long; SMALLINT соответствует short; REAL соответствует float; DOUBLE PRECISION соответствует double(именно такое соответствие утверждено в стандарте SQL/92).

Заметим еще, что в большинстве реализаций SQL поддерживаются некоторые дополнительные типы данных, например DATE, TIME, INTERVAL, MONEY. Некоторые из этих типов специфицированы в стандарте SQL/92, но в текущих реализациях синтаксические и семантические свойства таких типов могут различаться.

2.3 Структура запросов

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

<cursor specification> ::=
<query expression> [<order by clause>
<query expression> ::=
<query term>
| <query expression> UNION [ALL] <query term>
<query term> ::=
<query specification>
| (<query expression>)
<query specification> ::=
(SELECT [ALL | DISTINCT] <select list>
<table expression>)
<select statement> ::=
SELECT [ALL | DISTINCT] <select list>
INTO <select target list>
<table expression>
<subquery> ::=
(SELECT [ALL | DISTINCT] <result specification>
<table expression>
<table expression> ::=
<from clause>
[<where clause>]
[<group by clause>]
[<having clause>]

Язык допускает три типа синтаксических конструкций, начинающихся с ключевого слова SELECT: спецификация курсора (cursor specification), оператор выборки(select statement) и подзапрос (subquery). В основе каждой из них лежит синтаксическая конструкция "табличное выражение (table expression)".Семантика табличного выражения состоит в том, что на основе последовательного применения разделов from, where, group by и having из заданных в разделе from-таблиц строится некоторая новая результирующая таблица, порядок следования строк которой не определен и среди строк которой могут находиться дубликаты(т.е. в общем случае таблица-результат табличного выражения является мультимножеством строк). На самом деле именно структура табличного выражения в наибольшей степени характеризует структуру запросов языка SQL/89. Мы рассмотрим структуру и смысл разделов табличного выражения ниже, но до этого немного подробнее обсудим три упомянутые конструкции, включающие табличные выражения.

2.3.1 Спецификация курсора

Наиболее общей является конструкция "спецификация курсора". Курсор - это средство языка SQL, позволяющее с помощью набора специальных операторов получить построчный доступ к результату запроса к БД. К табличным выражениям, участвующим в спецификации курсора, не предъявляются какие-либо ограничения. Как видно из сводки синтаксических правил, при определении спецификации курсора используются три дополнительных конструкции: спецификация запроса, выражение запросов и раздел ORDER BY.

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

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

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

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

2.3.1.3 РАЗДЕЛ ORDER BY

Наконец, раздел ORDER BY позволяет установить желаемый порядок просмотра результата выражения запросов. Синтаксис ORDER BY следующий:

<order by clause> ::=
ORDER BY <sort specification>
[{,<sort specification>}...]
<sort specification> ::=
{<unsigned integer> | <column specification>}
[ASC | DESC]

Как видно из этих синтаксических правил, фактически задается список столбцов результата выражения запросов, и для каждого столбца указывается порядок просмотра строк результата в зависимости от значений этого столбца(ASC - по возрастанию (умолчание), DESC - по убыванию). Столбцы можно задавать их именами тогда и только тогда, когда (1) выражение запросов не содержит операций UNION или UNION ALL и (2) в списке выборки спецификации запроса этому столбцу соответствует арифметическое выражение, состоящее только из имени столбца. Во всех остальных случаях в разделе ORDER BY должен указываться порядковый номер столбца в таблице-результате выражения запросов.

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

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

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

2.3.3 Подзапрос

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

2.3.4 Табличное выражение

Стандарт SQL/89 рекомендует рассматривать вычисление табличного выражения как последовательное применение разделов FROM, WHERE, GROUP BY и HAVING к таблицам, заданным в списке FROM. Раздел FROM имеет следующий синтаксис:

<from clause> ::=
FROM <table reference>
[{,<table reference>}...]
<table reference> ::=
<table name> [<correlation name>]

2.3.4.1 РАЗДЕЛ FROM

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

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

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

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

2.3.4.2 РАЗДЕЛ 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 = unknown
unknown AND true = unknown
unknown AND unknown = unknown
true OR unknown = true
unknown OR true = true
unknown OR unknown = unknown
NOT unknown = unknown

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

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

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

<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 неопределенное значение выступает как специальный вид определенного значения, т.е. возможно, например, образование группы строк, значение указанного столбца которых является неопределенным. Для обеспечения переносимости прикладных программ нужно внимательно анализировать специфику работы с неопределенными значениями в конкретной СУБД.

2.3.4.2.2 Предикат 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)".

2.3.4.2.3 Предикат 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)".

2.3.4.2.4 Предикат 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".

2.3.4.2.5 Предикат null

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

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

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

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

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

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

2.3.4.2.7 Предикат exists

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

< exists predicate> ::=
EXISTS <subquery>

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

2.3.4.3 РАЗДЕЛ GROUP BY

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

< group by clause> ::=
GROUP BY <column specification>
[{, <column specification>}...]

Если обозначить через R таблицу, являющуюся результатом предыдущего раздела (FROM или WHERE), то результатом раздела GROUP BY является разбиение R на множество групп строк, которое состоит из минимального числа таких групп, в которых для каждого столбца из списка столбцов раздела GROUP BY во всех строках каждой группы, включающей более одной строки, значения этого столбца совпадают. Для обозначения результата раздела GROUP BY в стандарте используется термин "сгруппированная таблица".

2.3.4.4 РАЗДЕЛ HAVING

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

<having clause> ::=
HAVING <search condition>

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

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

Поэтому в арифметических выражениях предикатов, входящих в условие выборки раздела HAVING, прямо можно использовать только спецификации столбцов, указанных в качестве столбцов группирования в разделе GROUP BY. Остальные столбцы можно специфицировать только внутри спецификаций агрегатных функций COUNT, SUM, AVG, MIN и MAX, вычисляющих в данном случае некоторое агрегатное значение для всей группы строк. Аналогично обстоит дело с подзапросами, входящими в предикаты условия выборки раздела HAVING: если в подзапросе используется характеристика текущей группы, то она может задаваться только путем ссылки на столбцы группирования.

Результатом выполнения раздела HAVING является сгруппированная таблица, содержащая только те группы строк, для которых результат вычисления условия поиска есть true. В частности, если раздел HAVING присутствует в табличном выражении, не содержащем GROUP BY, то результатом его выполнения будет либо пустая таблица, либо результат выполнения предыдущих разделов табличного выражения, рассматриваемый как одна группа без столбцов группирования.

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

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

2. 3. 5. 1 СЕМАНТИКА АГРЕГАТНЫХ ФУНКЦИЙ

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

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

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

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

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

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

2. 3. 5. 2 РЕЗУЛЬТАТЫ ЗАПРОСОВ

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

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

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

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

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

2. 4 Средства определения схемы

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

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

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

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

2. 4. 1 Оператор определения схемы

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

<идентификатор полномочий>. <простое имя>

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

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

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

2. 4. 2 Определение таблицы

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

<table definition> ::=
CREATE TABLE <table name>
(<table element> [{, <table element>}. . . ])
<table element> ::=
<column definition>
| <table constraint definition>

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

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

2. 4. 2. 1 ОПРЕДЕЛЕНИЕ СТОЛБЦА

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

<column definition> ::=
<column name> <data type>
[<default clause>]
[<column constraint>. . . ]
<default clause> ::=
DEFAULT { <literal> | USER | NULL }
<column constraint> ::=
NOT NULL [<unique specification>]
| <references specification>
| CHECK (<search condition>)

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

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

Указание в разделе ограничений целостности NOT NULL приводит к неявному порождению проверочного ограничения целостности для всей таблицы (см. п. 2. 4. 2. 2) "CHECK (C IS NOT NULL)" (где C - имя данного столбца). Если ограничение NOT NULL не указано, и раздел умолчаний отсутствует, то неявно порождается раздел умолчаний DEFAULT NULL. Если указана спецификация уникальности, то порождается соответствующая спецификация уникальности для таблицы.

Если в разделе ограничений целостности указано ограничение по ссылкам данного столбца (<references specification>), то порождается соответствующее определение ограничения по ссылкам для таблицы: FOREIGN KEY(C) <references specification>.

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

2. 4. 2. 2 ОПРЕДЕЛЕНИЕ ОГРАНИЧЕНИЙ ЦЕЛОСНОСТИ ТАБЛИЦЫ

Раздел определения ограничений целостности таблицы обладает следующим синтаксисом:

<table constraint definition> ::=
<unique constraint definition>
| <referential constraint definition>
| <check constraint definition>
<unique constraint definition> ::=
<unique specification> (<unique column list>)
<unique specification> ::=
UNIQUE | PRIMARY KEY
<unique column list> ::=
<column name> [{, <column name>}. . . ]
<referential constraint definition> ::=
FOREIGN KEY (<referencing columns>)
<references specification>
<references specification> ::=
REFERENCES <referenced table and columns>
<referencing columns> ::=
<reference column list>
<referenced table and columns> ::=
<table name> [(<reference column list>)]
<reference column list> ::=
<column name> [{, <column name>}. . . ]
<check constraint definition> ::=
CHECK (<search condition>)

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

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

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

2. 4. 2. 2. 1 Ограничение уникальности

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

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

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

Ограничение по ссылкам от заданного набора столбцов 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. По-человечески это можно сформулировать так: ограничение по ссылкам удовлетворяется, если для каждой корректной ссылки существует объект, на который она ссылается. В привычной программистам терминологии, ограничение по ссылкам не позволяет производить "висячие" ссылки, не ведущие ни к какому объекту.

2. 4. 2. 2. 3 Проверочное ограничение

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

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

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

2. 4. 3 Определение представлений

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

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

<view definition> ::=
CREATE VIEW <table name> [(<view column list>)]
AS <query specification>
[WITH CHECK OPTION]
<view column list> ::=
<column name> [{, <column name>}. . . ]

Определяемая представляемая таблица V является изменяемой (т. е. по отношению к V можно использовать операторы DELETE и UPDATE) в том и только в том случае, если выполняются следующие условия для спецификации запроса:



Используются технологии uCoz