Стандарти мови реляційних баз даних 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 (lenght), де lenght задає довжину рядків даного типу. Зауважимо,
що в 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
не визначено. Значення предиката "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> SOME
S "має значення 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 являє собою "справжню"
згруповану таблицю, тобто табличне вираження містить розділ GROUP
BY і, отже, визначений принаймні один стовпець групування.
У цьому випадку правила формування списку вибірки повністю відповідають
правилам формування умови вибірки розділу 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) в тому і тільки в тому
випадку, якщо виконуються наступні умови для специфікації запиту:

  • в списку вибірки не вказано ключове слово DISTINCT;
  • кожне арифметичне вираження у списку вибірки являє собою
    одну специфікацію стовпця, і специфікація одного стовпця не з'являється
    більше одного разу;
  • в розділі FROM вказана тільки одна таблиця, яка є чи базова
    таблицею, або змінною представленої таблицею;
  • в умові вибірки розділу WHERE не використовуються вкладені запити;
  • в табличному вираженні відсутні розділи GROUP BY і HAVING.
  • Зауваження: ці обмеження є дуже сильними. У реалізаціях вони
    можуть бути ослаблені. Але якщо прагнути до мобільності, не слід користуватися
    розширеними можливостями.

    Якщо в списку вибірки специфікації запиту є хоча б одне арифметичне
    вираз, що складається не з однієї специфікації стовпця, або якщо ім'я хоча
    б одного стовпця бере участь у списку вибірки більше одного разу, визначення
    подання повинно містити список імен стовпців представляється таблиці.
    Більш просто, потрібно явно іменувати стовпці представляється таблиці, якщо
    ці імена не успадковуються від стовпців таблиць розділу FROM специфікації запиту.

    Вимога WITH CHECK OPTION у визначенні подання має сенс
    тільки у разі визначення змінною представляється таблиці, яка
    визначається специфікацією запиту, що містить розділ WHERE. При наявності
    цієї вимоги не допускаються зміни представляється таблиці, що призводять
    до появи в базових таблицях рядків, не видимих в спеціальній таблиці
    (Тобто таких рядків, які не задовольняють умові пошуку розділу WHERE
    специфікації запиту). Якщо WITH CHECK OPTION у визначенні подання
    відсутня, такий контроль не проводиться.

    2.4.4 Визначення привілеїв

    Відповідно до ідеології мови SQL контроль прав доступу даного
    користувача до таблиць БД проводиться на основі механізму привілеїв.
    Фактично, цей механізм полягає в тому, що для виконання будь-якої дії
    над таблицею користувач повинен мати відповідну привілеєм (реально
    всі можливі дії описуються фіксованим стандартним набором привілеїв).
    Користувач, що створив таблицю, автоматично стає власником всіх
    можливих привілеїв на виконання операцій над цією таблицею. У число
    цих привілеїв входить привілей на передачу всіх або деяких привілеїв
    по відношенню до даної таблиці іншому користувачеві, включаючи привілей
    на передачу привілеїв. Іноді підтримується і зворотна операція вилучення
    привілеїв від користувача, раніше їх отримав.

    У SQL/89 визначається спрощена схема механізму привілеїв. По-перше,
    "Роздача" привілеїв можлива тільки при визначенні таблиці.
    По-друге, користувач, який отримав деякі привілеї від інших користувачів,
    може передати їх далі тільки при визначенні схеми.

    Оператор визначення привілеїв володіє наступним синтаксисом:

    <privilege definition> ::=

    GRANT <privileges> ON <table name>

    TO <grantee> [{,<grantee>}…]

    [WITH GRANT OPTION]

    <privileges> ::=

    ALL PRIVILEGES

    | <action> [{,<action>}…]

    <action> ::=

    SELECT | INSERT | DELETE

    | UPDATE [(<grant column list>)]

    | REFERENCES [(<grant column list>]

    <grant column list> ::=

    <column name> [{,<column name>}…]

    <grantee> ::=

    PUBLIC | <authorization identifier>

    Ці синтаксичні правила досить ясно показують сенс механізму
    визначення привілеїв в SQL/89. Зауважимо лише, що необхідно володіти
    привілеєм REFERENCES по відношенню до вказаних стовпцях таблиці T1, щоб
    мати можливість при визначенні таблиці T специфікувати обмеження
    за посиланнями між цією таблицею і існуючої до цього моменту таблицею
    T1.

    Ще раз зауважимо, що, хоча в загальному сенсі у всіх SQL-орієнтованих
    СУБД підтримується механізм захисту даних на основі привілеїв доступу,
    реалізації можуть відрізнятися в деталях. Це знову те місце, яке потрібно
    локалізувати, якщо прагнути до створення мобільного прикладної системи.

    2.5 Мова модулів або вбудований SQL?

    У стандарті SQL/89 визначені два способи взаємодії з БД з прикладної
    програми, написаної на традиційній мові програмування (як ми вже
    згадували, SQL/89 орієнтований на використання спільно з мовами Кобол,
    Фортран, Паскаль і ПЛ / 1, але в реалізаціях зазвичай підтримується і мову
    Сі). Перший спосіб полягає в тому, що всі оператори SQL, з якими може
    працювати дана прикладна програма, зібрані в один модуль і оформлені
    як процедури цього модуля. Для цього SQL/89 містить спеціальний под'язик
    – Мова модулів. При використанні такого способу взаємодії з БД прикладна
    програма містить виклики процедур модуля SQL з передачею їм фактичних
    параметрів і отриманням відповідних параметрів.

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

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

    На відміну від цього, для операторів SQL, вбудованих в прикладну програму,
    компіляція цих операторів зазвичай проводиться кожного разу при їх використанні
    (Правильніше сказати, при кожному першому використанні оператора при даному
    запуску прикладної програми).

    Звичайно, користувачі не зобов'язані знати про це технічному відмінності
    в обробці двох видів взаємодії з СУБД. Існують і такі системи,
    які виробляють одноразову компіляцію вбудованих операторів SQL і зберігають
    відкомпільований код. Але все-таки краще мати це на увазі (зокрема,
    при компіляції оператора SQL безпосередньо перед його виконанням ймовірно
    отримання більш оптимального плану виконання оператора).

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

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

    2.5.1 Мова модулів

    Структура модуля SQL у стандарті SQL/89 визначається наступними синтаксичними
    правилами:

    <module> ::=

    <module name clause>

    <language clause>

    <module authorization clause>

    [<declare cursor>…]

    < procedure > …

    <module name clause> ::=

    MODULE [<module name>]

    <language clause> ::=

    LANGUAGE { COBOL | FORTRAN | PASCAL | PLI }

    <module authorization clause> ::=

    <PRE>AUTHORIZATION <module authorization identifier>

    <module authorization identifier> ::=

    <authorization identifier>

    Істотно, що кожен модуль SQL орієнтований на використання в програмах,
    написаних на конкретній мові програмування. Якщо в модулі присутні
    процедури роботи з курсором (див. п. 2.6.1), то всі курсори повинні бути
    специфіковані на початку модуля. Зауважимо, що оголошення курсору не занурюється
    в яку-небудь процедуру, оскільки це описовий, а не виконується оператор
    SQL (іншими словами, всі курсори будуть автоматично оголошені в самому
    початку виконання прикладної програми, пов'язаної з модулем SQL).

    2.5.1.1 ВИЗНАЧЕННЯ ПРОЦЕДУРИ

    Процедури в модулі SQL визначаються в наступному синтаксисі:

    <procedure> ::=

    PROCEDURE <procedure name>

    <parameter declaration>…;

    <SQL statement>;

    <parameter declaration>::=

    <parameter name> <data type>

    | <SQLCODE parameter>

    <SQLCODE parameter> ::=

    SQLCODE

    <SQL statement> ::=

    <close statement>

    | <commit statement>

    | <delete statement positioned>

    | <delete statement searched>

    | <fetch statement>

    | <insert statement>

    | <open statement>

    | <rollback statement>

    | <select statement>

    | <update statement positioned>

    | <update statement searched>

    Імена всіх процедур в одному модулі повинні бути різні. Будь-яке ім'я параметра,
    міститься в операторі SQL процедури, має бути специфікована в
    розділі оголошення параметрів. Число фактичних параметрів при виклику
    процедури повинно збігатися із числом формальних параметрів, зазначених при
    її оголошенні. Список формальних параметрів кожної процедури повинен містити
    рівно один параметр SQLCODE – код відповіді процедури; можливі значення
    кодів відповіді стандартизовані, але деякі (правильніше сказати, абсолютна
    більшість) з них визначаються в реалізації.

    2.5.2 Вбудований SQL

    Оскільки у стандарті SQL/89 не специфіковані (навіть у додатках)
    правила вбудовування SQL в мову Сі, ми наведемо тільки загальні синтаксичні
    правила вбудовування, використовувані для будь-якої мови. Це допоможе оцінити
    "Рівень стандартності" конкретної реалізації.

    <embedded SQL statement> ::=

    <SQL prefix>

    { <declare cursor>

    | <embedded exception declaration>

    | <SQL statement>}

    [<SQL terminator>]

    <SQL prefix> ::=

    EXEC SQL

    <SQL terminator> ::=

    END EXEC | ;

    <embedded SQL declare section> ::=

    <embedded SQL begin declare>

    [<host variable definition>…]

    <embedded SQL end declare>

    <embedded SQL begin declare> ::=

    <SQL prefix> BEGIN DECLARE SECTION

    [<SQL terminator>]

    <embedded SQL end declare> ::=

    <SQL prefix> END DECLARE SECTION

    [<SQL terminator>]

    <embedded variable name> ::=

    :<host identifier>

    <embedded exception declaration> ::=

    WHENEVER <condition> <exception action>

    <condition> ::=

    SQLERROR | NOT FOUND

    <exception action> ::=

    CONTINUE | <go to>

    <go to> ::=

    { GOTO | GO TO } <target>

    <target>:: =: <host identifier> | <unsigned integer>

    Вбудовувані оператори SQL, включаючи оголошення курсору, а також розділи
    оголошення виняткових ситуацій та змінних основної програми, повинні
    бути оточені дужками EXEC SQL і END EXEC. Оголошення курсору повинно зустрічатися
    текстуально раніше будь-якого оператора, що посилається на цей курсор. Всі змінні
    основної програми, використовувані у вбудованих операторах SQL, повинні бути
    оголошені в текстуально попередньому цього оператора розділі оголошення
    змінних основної програми. При цьому синтаксис оголошення змінної
    відповідає синтаксису основного мови програмування, але імені змінної
    передує двокрапка.

    Механізм обробки виняткових ситуацій в SQL/89 вкрай простий (можна
    сказати, примітивний). Можна задавати реакцію на виникнення двох видів
    умов: SQLERROR – це умова появи від'ємного значення у змінної
    SQLCODE після виконання вбудованого оператора; NOT FOUND – умова появи
    в SQLCODE значення +100 (цей код означає вичерпання результуючого безлічі
    запиту при його перегляді через курсор). Реакція може складатися у виконанні
    безумовного переходу на мітку основної програми (дія GO TO) або
    відсутнім (дія CONTINUE). Спрацьовує той оператор визначення
    реакції на виняткову ситуацію, який текстуально ближче від початку
    програми до даного оператору SQL.

    Зауважимо, що в багатьох реалізаціях підтримується два види кодів відповіді
    при виконанні операторів SQL (вбудованих або взятих з модуля): через
    змінну SQLCODE з кодами відповіді, що подаються цілими числами, і через
    змінну SQLSTATE з кодами відповіді, які кодуються десятковими числами,
    представленими в текстовій формі. Є тенденція до переходу на використання
    тільки механізму SQLSTATE, але в стандартних реалізаціях повинен підтримуватися
    і механізм SQLCODE.

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

    У стандарті SQL/89 визначений дуже обмежений набір операторів маніпулювання
    даними. Їх можна класифікувати на групи операторів, пов'язаних з курсором;
    одиночних операторів маніпулювання даними; і операторів завершення транзакції.
    Всі ці оператори можна використовувати як в модулях SQL, так і у вбудованому
    SQL. Зауважимо, що в SQL/89 не визначений набір операторів інтерактивного
    SQL (тобто відсутні явні специфікації набору операторів SQL, які
    можуть задаватися в інтерактивному режимі).

    2.6.1 Оператори, пов'язані з курсором

    Оператори цієї групи об'єднує те, що всі вони працюють з деякими
    курсором, оголошення якого має міститися в тому ж модулі або програмі
    з вбудованим SQL. Якщо говорити неформально, курсор – це механізм мови
    SQL, призначений для того, щоб дозволити прикладній програмі послідовно,
    рядок за рядком, переглянути результат пов'язаного з курсором запиту.

    2.6.1.1 ОПЕРАТОР оголошення курсору

    Для зручності ми повторимо тут синтаксичні правила оголошення курсору,
    наведені в підрозділі 2.3.1:

    <declare cursor> ::=

    DECLARE <cursor name> CURSOR

    FOR <cursor specification>

    <cursor specification> ::=

    <query expression> [<order by clause>…]

    <query expression> ::=

    <query term>

    | <query expression> UNION [ALL] <query term>

    <query term> ::=

    <query specification> | (<query expression>)

    <order by clause> ::=

    ORDER BY <sort specification>

    [{,<sort specification>}…]

    <sort specification> ::= 

    { <unsigned integer> | <column specification> }

    [ASC | DESC]

    В оголошенні курсору можуть задаватися запити найбільш загального вигляду з
    можливістю виконання операції UNION і сортування кінцевого результату.
    Цей оператор не є виконуваним, він тільки пов'язує ім'я курсору
    зі специфікацією курсору.

    2.6.1.2 ОПЕРАТОР відкриття курсору

    Оператор описується таким синтаксичним правилом:

    <open statement> ::=

    OPEN <cursor name>

    У реалізаціях вбудованого SQL звичайно потрібно, щоб оголошення курсору
    текстуально передувало оператору відкриття курсору. Оператор відкриття
    курсору повинен бути першим у серії виконуваних операторів, пов'язаних з
    заданим курсором. При виконанні цього оператора здійснюється підготовка
    курсору до роботи над ним. Зокрема, в цей момент проводиться зв'язування
    специфікації курсору зі значеннями змінних основного мови в разі
    вбудованого SQL або параметрів у випадку модуля (це означає, що після виконання
    оператора відкриття курсору будь-які зміни змінних основної програми
    не будуть надавати будь-які дії на результат запиту, пов'язаного
    з курсором).

    У більшості реалізацій у випадку вбудованого SQL саме виконання
    оператора відкриття курсору призводить до компіляції специфікації курсору і
    підготовки виконуваного плану запиту. Можна вважати (хоча фактично це
    робиться далеко не завжди), що під час виконання оператора відкриття
    курсору проводиться побудова тимчасової таблиці, яка містить результат
    запиту, який пов'язаний з цим курсором.

    Наступні оператори можна виконувати над відкритим курсором в довільному
    порядку.

    2.6.1.3 ОПЕРАТОР ЧИТАННЯ ЧЕРГОВИЙ рядок курсору

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

    <fetch statement> ::=

    FETCH <cursor name> INTO <fetch target list>

    <fetch target list> ::=

    <target specification>[{,<target specification>}…]

    У операторі читання вказується ім'я курсору і обов'язковий розділ INTO,
    містить список специфікацій призначення (список імен змінних основної
    програми у випадку вбудованого SQL або імен "вихідних" параметрів
    у разі модуля SQL). Число і типи даних у списку призначень повинні збігатися
    з числом і типами даних списку вибірки специфікації курсору.

    Будь-який відкритий курсор завжди має позицію: він може бути встановлений
    перед деякої рядком результуючої таблиці (перед першим рядком відразу
    після відкриття курсору), на деяку рядок результату або за останньою
    рядком результату.

    Якщо таблиця, на яку вказує курсор, є порожньою, або курсор
    позиціонується на останній рядок або за нею, то при виконанні оператора
    читання курсор встановлюється в позицію після останнього рядка, параметру
    SQLCODE присвоюється значення 100, ніякі значення не присвоюються цілям,
    зазначеним у розділі INTO.

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

    Якщо курсор встановлений на рядок r, відмінну від останньої рядки, то
    курсор встановлюється на рядок, безпосередньо наступну за рядком
    r (у порядку, визначеному реалізацією, якщо запит не містить розділу
    ORDER BY), і значення з цієї наступного рядка присвоюються відповідним
    цілям.

    Виникає природне запитання, яким чином можна параметризовані курсор
    невизначеним значенням або дізнатися, що вибране з чергового рядка
    значення є невизначеним. Це досягається в SQL/89 за рахунок використання
    так званих індикаторних параметрів і змінних. Якщо відомо, що
    значення, що передається з основної програми СУБД або прийняте основний
    програмою від СУБД, може бути невизначеним, і цей факт цікавить прикладного
    програміста, то є специфікація параметра в операторі SQL має вигляд: <parameter
    name> [INDICATOR] <parameter name>, а специфікація змінної – <embedded
    variable name> [INDICATOR] <embedded variable name>. Негативне
    значення індикаторного параметра або індикаторного змінної (вони повинні
    бути цілого типу) відповідає невизначеному значенню параметра або
    змінної.

    2.6.1.4 ОПЕРАТОР ПОЗИЦІЙНІ ВИДАЛЕННЯ

    Синтаксис цього оператора наступний:

    <delete statement: positioned> ::=

    DELETE FROM <table name>

    WHERE CURRENT OF <cursor name>

    Якщо вказаний в операторі курсор відкритий і встановлений на деяку рядок,
    і курсор визначає змінну таблицю, то поточна рядок курсору видаляється,
    а він позиціонується перед наступним рядком. Таблиця, зазначена в розділі
    FROM оператора DELETE, повинна бути таблицею, зазначеної в самому зовнішньому
    розділі FROM специфікації курсору.

    2.6.1.5 ОПЕРАТОР ПОЗИЦІЙНІ МОДИФІКАЦІЇ

    Оператор описується такими синтаксичними правилами:

    <update statement: positioned> ::=

    UPDATE <table name>

    SET <set clause:positioned>

    [{,<set clause:positioned>}…]

    WHERE CURRENT OF <cursor name>

    <set clause: positioned> ::=

    <object column:positioned> =

    { <value expression> | NULL }

    <object column: positioned> ::= <column name>

    Якщо вказаний в операторі курсор відкритий і встановлений на деяку рядок
    і курсор визначає змінну таблицю, то поточна рядок курсору модифікується
    відповідно до розділу SET. Позиція курсору не змінюється. Таблиця,
    зазначена в розділі FROM оператора DELETE, повинна бути таблицею, зазначеної
    в самому зовнішньому розділі FROM специфікації курсору.

    Зауваження: вимога вказувати ім'я таблиці в операторах позиційного
    видалення і позиційної модифікації є, очевидно, надлишковим, оскільки
    до імені таблиці можна добратися через ім'я курсору. Єдиною можливою
    причиною цієї надмірності може бути спрощення реалізації (хоча не дуже
    зрозуміло, що саме спрощується).

    2.6.1.6 ОПЕРАТОР ЗАКРИТТЯ КУРСОР

    Синтаксис цього оператора наступний:

    <close statement>::=

    CLOSE <cursor name>

    Якщо до моменту виконання цього оператора курсор перебував у відкритому
    стані, то оператор переводить курсор в закритий стан. Після цього
    над курсором можливе виконання тільки оператора OPEN.

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

    Кожен з операторів цієї групи є абсолютно незалежним від будь
    б то не було іншого оператора, тобто для виконання будь-якого оператора цієї
    групи не потрібно попереднє виконання якого б то не було іншого
    оператора.

    2.6.2.1 ОПЕРАТОР ВИБІРКИ

    Для зручності читачів ми повторюємо синтаксис цього оператора ще раз:

    <select statement> ::=

    SELECT [ALL | DISTINCT] <select name>

    INTO <select target list>

    <table expression>

    <select target list>::=

    <target specification> [{, <target specification> }…]

    Оскільки, як ми вже пояснювали в підрозділі 2.3.2, результатом одиночного
    оператора вибірки повинна бути таблиця, що складається не більше, ніж з однієї
    рядки, список цілей специфікується в самому операторові. Після виконання
    оператора мети містять відповідні поля (стовпці) результуючої рядки
    (Якщо, звичайно, результуюча таблиця не є порожнім).

    2.6.2.2 ОПЕРАТОР ПОШУКОВОЇ ВИДАЛЕННЯ

    Оператор описується таким синтаксичним правилом:

    <delete statement: searched> ::=

    DELETE FROM <table name>

    WHERE [<search condition>]

    Таблиця T, зазначена в розділі FROM оператора DELETE, повинна бути змінною.
    На умова пошуку накладається умова, що на стовпці таблиці T не
    повинні міститися посилання ні в якому вкладеному підзапит предикатів розділу
    WHERE.

    Фактично, оператор виконується таким чином: послідовно
    проглядаються всі рядки таблиці T, і ті рядки, для яких результатом
    обчислення умови вибірки є true, видаляються з таблиці T. За відсутності
    розділу WHERE видаляються всі рядки таблиці T (зазвичай при виконанні пошукового
    оператора DELETE без розділу WHERE в інтерактивному режимі до видалення всіх
    рядків запитується підтвердження правильності такої дії).

    2.6.2.3 ОПЕРАТОР ПОШУКОВОЇ МОДИФІКАЦІЇ

    Оператор володіє наступним синтаксисом:

    <update statement: searched> ::=

    UPDATE <table name>

    SET <set clause: searched>

    [{,<set clause: searched>}…]

    [WHERE <search conditions>]

    <set clause: searched> ::=

    <object column: searched> =

    { <value expression> | NULL }

    <object column: searched> ::= <column name>

    Таблиця T, зазначена в операторі UPDATE, повинна бути змінною. На
    умова пошуку накладається умова, що на стовпці таблиці T не повинні
    міститися посилання ні в якому вкладеному підзапит предикатів розділу WHERE.

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

    2.6.3 Оператори закінчення транзакції

    Поточна транзакція може бути завершена успішно (з фіксацією в базі
    даних проведених змін) шляхом виконання оператора COMMIT WORK
    або аварійно (з вилученням з бази даних змін, зроблених поточної
    транзакцією) шляхом виконання оператора ROLLBACK WORK. При виконанні будь-якого
    з цих операторів здійснюється примусове закриття всіх курсорів,
    відкритих до моменту виконання оператора завершення транзакції.

    3. Динамічний SQL в Oracle V.6

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

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

    Один з можливих шляхів розширення полягає у використанні спеціальної
    групи операторів, які забезпечують динамічну компіляцію (під час виконання
    прикладної програми) базового підмножини операторів SQL і підтримуючих
    їх коректне виконання. Деякий набір таких операторів входив в діалект
    SQL, реалізований в System R, відмінний набір входить у реалізацію
    Oracle V.6, і, нарешті, в новому стандарті SQL/92 з'явилася стандартна
    версія динамічного SQL.

    Оскільки в СУБД Oracle засоби динамічного SQL реалізовані вже порівняно
    давно, має сенс розглянути спочатку їх, щоб мати підстави для порівняння
    з SQL/92.

    Зауваження: ми говоримо тут саме про Oracle V.6, а не про останню,
    сьомої версії, оскільки в Oracle V.7 є реалізація динамічного
    SQL, що відповідає стандарту SQL/92.

    У додатковий набір операторів, що підтримують динамічну компіляцію
    базових операторів SQL, входять оператори: PREPARE, DESCRIBE і EXECUTE.

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

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

    <prepare-statement> ::=

    PREPARE <statement-name> FROM <host-string-variable>

    <statement-name> ::= <name>

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

    На відміну від операторів SQL, статично підставляється в програму на
    звичайній мові програмування, в яких зв'язок із змінними включає
    програми проводиться по іменах (тобто відповідно до стандарту під
    вбудованому операторі SQL можуть вживатися просто імена змінних включає
    програми), динамічна природа операторів, що готуються за допомогою
    оператора PREPARE, змушує розглядати ці імена як імена формальних
    параметрів. Відповідність цих формальних параметрів адресами змінних
    включаючи програми встановлюється позиційно під час виконання підготовленого
    оператора.

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

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

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

    3.3 Оператор виконання підготовленого оператора

    Оператор EXECUTE служить для виконання раніше підготовленого оператора
    SQL типу "N" (не вимагає застосування курсору) або для сумісної підготовки
    та виконання такого оператора. Синтаксис оператора EXECUTE:

    <execute-statement> ::=

    EXECUTE

    { <statement-name> [USING <host-vars-list>]

    | IMMEDIATE <host-string-variable> }

    Для виконання підготовленого оператора служить перший варіант оператора
    EXECUTE. У цьому випадку <statement-name> повинен вказати ім'я, вживалося
    раніше в операторі PREPARE. Якщо в підготовленому операторі присутні
    формальні параметри, то в операторі EXECUTE повинен задаватися список фактичних
    параметрів <host-vars-list>. Число і типи фактичних параметрів
    повинні відповідати числу і типам формальних параметрів підготовленого
    оператора.

    Другий варіант оператора EXECUTE призначений для сумісної підготовки
    і виконання оператора SQL типу "N". У цьому випадку параметром оператора
    EXECUTE є рядок, яка повинна містити текст оператора SQL (цю
    рядок дозволяється також задавати літерально). Забороняється використання
    в цьому операторі змінних включаючи програми (формальних параметрів).

    3.4 Робота з динамічними операторами SQL через
    курсори

    Для використання таких операторів використовується розширення механізму
    курсорів стандарту SQL. По-перше, при визначенні курсора можна вказувати
    не тільки літеральну специфікацію курсору, а й ім'я оператора, що вводиться
    за допомогою оператора PREPARE (у цьому випадку оператор PREPARE повинен текстуально
    знаходитися вище оператора DECLARE). Тим самим повний синтаксис оператора
    DECLARE стає наступним:

    <declare cursor> ::=

    DECLARE <cursor name> CURSOR

    FOR { <cursor specification> | <statement-name> }

    Далі, оскільки для такого курсору в статиці невідома інформація
    про вхідних і вихідних змінних включаючи програми, то використовується інша
    форма операторів OPEN і FETCH.

    Повний синтаксис цих операторів стає наступним:

    <open statement> ::=

    OPEN <cursor name>

    [USING {<host-vars-list> | DESCRIPTOR <descr-name>}]

    <fetch statement> ::=

    FETCH <cursor name>

    { INTO <fetch target list> |

    USING <host-vars-list> |

    USING DESCRIPTOR <descr-name> }

    Як видно, пропонується два способи завдання фактичних вхідних і вихідних
    параметрів: пряме з вказівкою в операторах OPEN та / або FETCH списків імен
    змінних включаючи програми і непряме, коли число параметрів і їх
    адреси повідомляються через додаткову структуру-дескриптор.

    Перший спосіб пропонується використовувати для роботи з операторами вибірки,
    для яких фіксований набір формальних вхідних і вихідних параметрів.
    Точніше кажучи, що стосується вихідних параметрів, повинні бути фіксовані
    число і типи елементів списку вибірки.

    Другий спосіб роботи з динамічно відкомпілювалися операторами, які вимагають
    використання курсорів, полягає у використанні дескрипторів динамічно
    формованих списків параметрів. У цьому випадку вся відповідальність за відповідність
    типів фактичних і формальних параметрів лягає на програміста. У результаті
    помилки при формуванні такого списку, зокрема, може бути зіпсована
    пам'ять Сі-програми.

    4. Деякі риси SQL/92

    Величезний обсяг стандарту SQL/92 і обмежений обсяг цієї статті не
    дозволяють нам описати цей стандарт скільки-небудь докладно. Крім того,
    як зазначалося вище, на сьогоднішній день все ще відсутня яка б то
    не було повна реалізація SQL/92. Тим не менше ми вважаємо корисним порівняно
    докладно описати стандартні засоби динамічного SQL (цей опис можна
    використовувати хоча б як еталон при порівнянні різних реалізацій)
    і привести зведення основних відмінностей SQL/92 від SQL/89 (в цьому ми будемо слідувати
    останнього видання книги Дейта "Стандарт SQL").

    4.1 Динамічний SQL у стандарті SQL/92

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

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

    Оператор має наступний синтаксис:

    <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 стовпців результату запиту), то це призводить до виникнення виняткової
    ситуації.

    4.1.2 Оператор звільнення пам'яті з-під дескриптора

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

    <deallocate descriptor statement> ::=

    DEALLOCATE DESCRIPTOR <descriptor name>

    Виконання цього оператора приводить до звільнення пам'яті з-під раніше
    виділеного дескриптора. Після цього використання імені дескриптора незаконно
    будь-який оператор, крім ALLOCATE DESCRIPTOR.

    4.1.3 Оператор одержання інформації з області дескриптора 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 (див. п.
    4.1.7). За одне виконання оператора можна отримати або число заповнених
    елементів дескриптора (COUNT), або інформацію, що міститься в одному з
    заповнених елементів.

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

    Оператор установки має наступний синтаксис:

    <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 (число заповнених елементів)
    або частково або повністю сформувати один елемент дескриптора.

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

    Оператор визначається наступним синтаксисом:

    <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 і DEALLOCATE
    PREPARE. Цей зв'язок зберігається до явного виконання оператора DEALLOCATE
    PREPARE.

    4.1.6 Оператор відмови від підготовленого оператора

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

    <deallocate prepared statement> ::=

    DEALLOCATE PREPARE <SQL statement name>

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

    4.1.7 Оператор запиту опису підготовленого
    оператора

    Оператор визначається наступним синтаксисом:

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

    4.1.8 Оператор виконання підготовленого оператора

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

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

    4.1.9 Оператор підготовки з негайним виконанням

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

    <execute immediate statement> ::=

    EXECUTE IMMEDIATE <SQL statement variable>

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

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

    Оператор визначається наступним синтаксисом:

    <dynamic declare cursor> ::=

    DECLARE <cursor name> [INSENSITIVE] [SCROLL]

    CURSOR FOR <statement name>

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

    4.1.11 Інший різновид оператора визначення курсору над динамічно
    підготовленим оператором вибірки

    Для цього оператора діють такі синтаксичні правила:

    <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> відноситься до області видимості імен: у межах
    поточного модуля або в межах поточної сесії.

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

    Синтаксис оператора відкриття курсору наступний:

    <dynamic open statement> ::=

    OPEN <dynamic cursor name> [<using clause>]

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

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

    Синтаксис:

    <dynamic fetch statement> ::=

    FETCH [[<fetch orientation>] FROM]

    <dynamic cursor name> <using clause>

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

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

    Оператор закриття курсору визначається наступним синтаксичним правилом:

    <dynamic close statement> ::=

    CLOSE <dynamic cursor name>

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

    4.1.15 Оператор позиційного видалення по курсору, пов'язаному з динамічно
    підготовленим оператором вибірки

    Синтаксис:

    <dynamic delete statement: positioned> ::=

    DELETE FROM <table name>

    WHERE CURRENT OF <dynamic cursor name>

    Оператор позиційного видалення по курсору, пов'язаному з динамічно
    підготовленим оператором SQL, відрізняється від статичного випадку тільки
    тим, що ім'я курсору може задаватися через змінну.

    4.1.16 Оператор позиційної модифікації по курсору, пов'язаному з динамічно
    підготовленим оператором вибірки

    Оператор визначається наступним синтаксичним правилом:

    <dynamic update statement: positioned> ::=

    UPDATE <table name>

    SET <set clause> [{<comma> <set clause>}…]

    WHERE CURRENT OF <dynamic cursor name>

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

    4.1.17 Підготовлювані оператор позиційного
    видалення

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

    <preparable dynamic delete statement: positioned> ::=

    DELETE [FROM <table name>]

    WHERE CURRENT OF <cursor name>

    Основний сенс появи цього і наступного операторів полягає в тому,
    що поєднання курсору, визначеного на динамічно підготовленому операторі
    вибірки, і статично задаються операторах видалення та модифікації з цього
    курсору, виглядає досить безглуздо. Тому в стандарті з'явилися динамічно
    підготовлювані позиційні оператори видалення та вставки. Природно,
    що виконуватися вони повинні з допомогою оператора EXECUTE.

    4.1.18 Підготовлювані оператор позиційної модифікації

    <preparable dynamic update statement: positioned> ::=

    UPDATE [<table name>]

    SET <set clause> [{<comma> <set clause>}…]

    WHERE CURRENT OF <cursor name>

    Див. п. 4.1.17.

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

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

  • обмежитися підмножиною операторів динамічного SQL, реалізованим
    в Oracle V.6;
  • локалізувати частини програми, пов'язані з роботою з дескрипторами (тобто
    як мінімум не допускати прямої роботи з полями області дескрипторів в
    стилі Oracle).
  • 4.2 Зведення відмінностей SQL/92 від SQL/89

    У цьому розділі міститься коротке зведення відмінностей між SQL/92 і SQL/89.
    Синтаксичні та семантичні деталі конструкцій SQL/92 не наводяться.
    Ще раз підкреслимо, що у викладі ми слідуємо книзі Дейта "Стандарт
    SQL".

    4.2.1 Розширення мови

    У мові, визначеному стандартом SQL/92, міститься багато властивостей, які
    були відсутні в мові SQL/89. Нижче наводиться коротке зведення цих властивостей.

    4.2.1.1 ТИПИ ДАНИХ

    З'явилася можливість використання типу даних символьних рядків змінної
    довжини (тобто при специфікації стовпця вказується гранично допустимий розмір
    збереженої рядки в символах, а реально в базі даних зберігається рівно стільки
    символів, скільки їх ввів користувач). Введено типи даних бітових рядків
    постійної і змінної довжини (як вони реально зберігаються в базі даних,
    в стандарті не визначається). Нарешті, стандартизовані темпоральні типи
    даних DATE (дата), TIME (час) і INTERVAL (часовий інтервал).

    4.2.1.2 ІНТЕРНАЦІОНАЛІЗАЦІЯ І НАЦІОНАЛІЗАЦІЯ

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

    4.2.1.3 ВИЗНАЧЕННЯ СХЕМИ БД І маніпулювання схемою БД

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

    4.2.1.4 ОБМЕЖЕННЯ цілосності

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

    З'явилася можливість визначення відкладених (перевіряються при завершенні
    транзакції) обмежень цілісності.

    Розширені можливості визначення обмежень зовнішнього ключа (обмежень
    посилальної цілісності).

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

    4.2.1.5 УЯВЛЕННЯ

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

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

    4.2.1.6 Табличний ВИРАЖЕННЯ

    З'явилися можливості іменування стовпців результуючої таблиці і самої
    таблиці. Іменовані табличні вирази можна використовувати, зокрема,
    в розділі FROM запитів. (Раніше завжди було незрозуміло, чому табличне
    вираз, результатом якого за визначенням є таблиця, не можна
    використовувати в якості елемента списку розділу FROM.)

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

    4.2.1.7 ВИРАЖЕННЯ ЗАПИТІВ

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

    4.2.1.8 КУРСОР

    При визначенні курсора можна указувати ключові слова SCROLL і INSENSITIVE.
    Вказівка SCROLL означає, що курсор можна явно позиціонувати: на першу
    рядок результуючого безлічі запиту, на останній рядок, на рядок
    з позицією з позитивним чи негативним зсувом від поточного рядка,
    на рядок з явно вказаними абсолютним номером позиції. Наявність ключового
    слова INSENSITIVE означає, що які б зміни в базових таблицях не
    вироблялися в тій же транзакції, в якій визначено курсор, вони не повинні
    впливати на результуюче безліч рядків курсору після його відкриття. Зауважимо,
    що, хоча зовні ці можливості виглядають дуже привабливо, їх реалізація
    коштує недешево. І в тому і в іншому випадку потрібно явне і майже завжди
    повне побудова результуючого безлічі запиту, пов'язаного з курсором.

    4.2.1.9 управління транзакціями і РІВНІ ІЗОЛЯЦІЇ

    Відомо, що в більшості 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 і READ
    UNCOMMITTED є неприпустимою.

    4.2.1.10 ДИНАМІЧНИЙ SQL

    У стандарті визначені оператори динамічного SQL. Див. розд. 4.1.

    4.2.1.11 ВБУДОВАНИЙ SQL

    Як зазначалося в розд. 2.5, стандарт SQL/89 формально не включав розділ,
    присвячений вбудовуванню конструкцій SQL в програму на традиційній мові
    програмування. Цей розділ був додатком і, крім того, не включав
    правил вбудовування для мов Сі і Ада. У SQL/92 повністю специфіковані
    правила вбудовування для найбільш поширених мов програмування
    (Ада, Сі, Кобол, Фортран, MUMPS, Паскаль, ПЛ / 1).

    4.2.1.12 ІНТЕРАКТИВНИЙ (ПРЯМИЙ) SQL

    У SQL/92 специфікований набір операторів SQL, що повинні підтримуватися
    в інтерактивному режимі, хоча деякі рішення, як і раніше віддаються на
    відкуп реалізаціям.

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

    4.2.2 Несумісність

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

    5. Підсумок можливостей SQL-3

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

    5.1 Типи даних

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

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

    Передбачається включення в мову можливості використовувати певні
    користувачами типи даних. Мабуть, будуть наявні можливості визначення
    абстрактних типів даних з довільно складною внутрішньою структурою на
    основі таких традиційних специфікацій агрегування та структуризації,
    як LIST, ARRAY, SET, MULTISET і TURPLE, а також можливості визначення
    об'єктних типів з відповідними методами в стилі об'єктно-орієнтованого
    підходу.

    З'являється можливість використання принципів наслідування властивостей
    існуючої таблиці (супертабліци) при визначенні нової таблиці (підтаблиці).
    Підтаблиця успадковує від супертабліци всі визначення стовпців і первинного
    ключа. Інша можливість – створити таблицю, "подібну" існуючої
    в тому сенсі, що в новій таблиці успадковуються визначення деяких стовпців
    існуючої таблиці.

    5.2 Деякі інші властивості SQL-3

    Однією з проблем реалізації мови SQL завжди була проблема розпізнавання
    "Змінності" з'єднань. Як відомо, якщо подання включає
    з'єднання загального вигляду, то теоретично неможливо визначити, чи можна
    однозначно інтерпретувати операції оновлення такого подання. Однак
    існує кілька важливих класів сполук, які свідомо є
    змінюваними. У SQL-3 передбачається виділити ці класи за допомогою спеціальних
    синтаксичних конструкцій.

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

    Що стосується управління транзакціями, то відбувається повернення до старої
    ідеї System R про можливість установки всередині транзакції точок збереження
    (Savepoints). У операторі ROLLBACK можна вказати ідентифікатор раніше встановленої
    точки збереження, і тоді буде проведений відкат транзакції не до її початку,
    а до цієї точки збереження.

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

    6. Висновок

    Напевно, багатьом читачам ця стаття здалася дуже нудною. Що
    поробиш, важко писати захопливо, коли мова йде про стандарти. Вони
    нудні, але дуже корисні. Звичайно, мова SQL не відноситься до сімейства найбільш
    красивих, елегантних, зрозумілих і приємних винаходів людства. У SQL,
    мабуть, більше недругів, ніж друзів. Тим не менше саме ця мова лежить
    в основі сучасних систем управління базами даних, і в найближчому майбутньому
    ця ситуація збережеться. (Насправді, з'являється відчуття, що повністю
    від стилю SQL не вдасться звільнитися вже ніколи.) Тому, шановні пані
    та панове, давайте грунтовно освоювати стандарти мови SQL і проектувати
    і розробляти реально стерпні інформаційні системи.

    Сергій Дмитрович Кузнецов, тел.: 932-92-12

    Схожі статті:


    Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

    Коментарів поки що немає.

    Ваш отзыв

    Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

    *

    *