- •7. Ограничения уникальности
- •7. Ссылочная целостность и er-диаграммы
- •7. Ограничения ссылочной целостности
- •7. Ограничения других видов.
- •17. Минимальное покрытие множества функциональных зависимостей
- •27. Многозначные зависимости. Теорема Фейджина. Четвертая нормальная форма
- •27. Лемма Фейджина
- •27. Теорема Фейджина
- •37. Подзапросы
- •37. Коррелированные подзапросы
- •Простые объявления схем отношений
- •Модификация реляционных схем
- •Значения по умолчанию
- •Индексы
Значения по умолчанию
Иногда в момент создания или модификации кортежа значения некоторых его компонентов не известны. В примере 6.40 рассматривалась ситуация, связанная с добавлением в схему отношения нового атрибута. Если отношение уже содержит кортежи, система не "знает" о том, какие конкретные значения следует присвоить вновь созданным компонентам этих кортежей, и предлагает воспользоваться значениями null. Аналогичная ситуация возникает и при выполнении команды вставки кортежа в отношение studio, когда известно только название киностудии, а ее адрес и сертификационный номер президента — нет (см. пример 6.35 на с. 292).
Для преодоления подобных проблем в SQL используется значение null, автоматически присваиваемое любому компоненту, точное значение которого в данный момент не известно, — за исключением некоторых ситуаций, когда null применять нельзя (см. раздел 7.1 на с. 318). Однако подчас было бы целесообразно предпочесть иное значение, которое должно предлагаться системой по умолчанию (default value), если никакие другие значения, подходящие для присваивания конкретному компоненту, не известны.
Вообще говоря, любую инструкцию, в которой определяется название атрибута и его тип, можно сопроводить служебным словом default и соответствующим значением. В качестве значения допустимо вводить null или какую-либо константу (в некоторых случаях система предлагает и иные варианты — например, значение текущего момента времени).
Индексы
Индекс (index) атрибута А некоторого отношения R — это структура данных, позво ляющая повысить эффективность процедуры отыскания некоторого конкретного зна чения, хранимого в компонентах атрибута А. Наличие индекса обычно способно при
вести к существенному уменьшению времени обработки запросов, в которых значения атрибута Л сравниваются с константами посредством выражений, таких, как, скажем, А = 3 или даже А < 3. Технологиям создания индексов для крупных отношений в процессе реализации СУБД отводится весьма важная роль.
57. Курсоры
Наиболее универсальный способ объединения фрагментов кода базового языка с инструкциями SQL связан с объявлением курсора (cursor), позволяющего последовательно "просматривать" кортежи отношения. Отношением в данном случае может быть хранимая таблица или набор данных, сгенерированный системой в результате обработки запроса. Чтобы воспользоваться механизмом курсора, необходимо выполнить ряд действий, указанных ниже.
1. Объявить курсор. Простейшая форма объявления курсора состоит из следующих частей:
начального предложения exec sql, используемого для "внедрения" инструкций SQL в код базовой программы;
служебного слова declare;
наименования С курсора;
пары служебных слов cursor for;
выражения Q, представляющего собой наименование отношения или текст запроса вида "select—from—where", возвращающего отношение. Будучи объявленным и открытым (opened), курсор предоставляет возможность "перемещения" по кортежам отношения Q — после выполнения программой инструкции извлечения (fetch) кортежа курсор будет содержать ссылку на текущий кортеж отношения.
Иными словами, выражение объявления курсора можно представить так: exec sql declare С cursor for Q;
Открыть курсор. Инструкция открытия курсора С выглядит следующим образом:
exec sql open с;
После открытия курсор инициализируется и его внутренний "указатель" устанавливается таким образом, чтобы курсор давал возможность извлечь первый кортеж отношения.
Выполнить одну или несколько команд извлечения (fetch) кортежа. Назначение команды состоит в получении очередного кортежа отношения, которое указано в объявлении курсора. Если на некотором шаге множество кортежей оказывается исчерпанным, т.е. команда извлечения не способна возвратить очередной кортеж, в переменную sqlstate заносится код '02 000', означающий, что "кортеж не найден". Команда извлечения кортежа состоит из следующих частей:
служебных слов exec sql fetch from;
наименования С курсора;
служебного слова into;
списка L общих переменных. Если кортеж, подлежащий извлечению, существует, содержимое компонентов кортежа присваивается переменным в соответствии с порядком следования их в списке.
Другими словами, команду извлечения кортежа можно представить так:
exec sql fetch from С into L\
4. Закрыть курсор. Инструкция закрытия курсора С выглядит следующим образом:
exec sql close с;
После закрытия курсор не способен реагировать на команды извлечения кортежей.
Модификация данных посредством курсоров
Если курсор открыт для базовой таблицы {а не для виртуальной таблицы либо отношения, возвращаемого в результате обработки запроса), с его помощью вполне допустимо не только считывать и обрабатывать содержимое кортежей, но и удалять (delete) или обновлять (update) их.. Единственное исключение связано с конструкцией предложения where. При использовании команд модификации в контексте курсора предложение where принимает вид
where current of С
где С — наименование курсора.
Защита данных курсора от внешних воздействий
Предположим, что во время выполнения функции worthRanges, вычисляющей распределение значений доходов руководящих лиц, некоторый другой процесс, протекающий параллельно, модифицирует содержимое того же отношения MovieExec. Давайте примем следующую ситуацию как должное: существует некий "сторонний" процесс, пытающийся модифицировать отношение в тот момент, когда наша программа использует данные этого отношения для собственных нужд.
Что можно предпринять в подобном случае? Как кажется, почти ничего. Получиї статистические данные, мы, вероятно, будем пребывать в счастливом неведении, даже не догадываясь о том, что некоторые кортежи, которые, как мы полагаем, наша программа с успехом обработала, на самом деле были удалены другим приложением. Hf первый взгляд, остается просто доверять той информации, которую способен возвратить созданный нами курсор.
8.1.9. Изменение порядка просмотра содержимого курсора
Курсор может быть снабжен механизмом, позволяющим выбирать способ "перемещения" по кортежам отношения, лежащего в основе определения курсора. По умолчанию (и это удобно в большинстве ситуаций) система предлагает начать просмотр содержимого курсора с первого кортежа и извлекать кортежи в естественном порядке их следования, вплоть до достижения завершающего кортежа. В некоторых ситуациях требуется изменять порядок обработки либо на протяжении сеанса открытия курсора обращаться к одним и тем кортежам несколько раз.48 Чтобы воспользоваться подобными возможностями, надлежит выполнить два действия.
Включить в конструкцию объявления курсора (непосредственно перед словом cursor) служебное слово scroll, свидетельствующее о том, что курсор должен позволять "пролистывание" его содержимого в произвольном порядке, отличном от линейного, предлагаемого по умолчанию.
Сопроводить служебное слово FETCH в одноименной команде одним из перечисленных ниже слов, соответствующих требуемому режиму "перемещения" внутри курсора:
next или prior — для перемещения соответственно к следующему или предыдущему кортежу относительно текущего; если ни одно из служебных слов, указывающих "направление" перемещения, не задано, по умолчанию, как наиболее уместный, подразумевается режим next;
first или last — для перемещения соответственно к первому или последнему кортежу;
relative п (где п — целое значение) — для перемещения на п позиций вперед (если п положительно) или на п позиций назад (если п отрицательно)
относительно текущего кортежа; например, relative і — это синоним next, a relative -і — синоним prior;
d) absolute п (где п — целое значение) — для перемещения на п позиций вперед, начиная с нулевой (если п положительно), или на п позиций назад, начиная с позиции, следующей за завершающим кортежем (если п отрицательно); например, absolute 1 — это синоним first, a absolute -і — синоним last.
57. Динамический SQL
До сих пор, говоря о "внедрении" команд SQL в код программы, написанной на базовом языке, мы полагали, что текст SQL известен заранее. Альтернативный подход, более гибкий и многообещающий, предусматривает, что
EXEC SQL FETCH LAST FROM execCursor INTO :execName, :execAddr, :certNo, : worth. ;
while{1} {
/* Те же строки 10-14 */
EXEC SQL FETCH PRIOR FROM execCursor INTO :execName, :execAddr, :certNo, :worth;
}
Рис. 8.6. Пример процедуры просмотра кортежей в "обратном" порядке
выражения SQL создаются и выполняются динамически в процессе работы программы. Эти выражения не известны в период компиляции программы, поэтому обработке препроцессором они не подвергаются.
Примером подобной программы может служить приложение, которое запрашивает текст команды SQL у пользователя, а затем считывает и выполняет ее. На протяжении главы 6 (см. с. 249~316)мы подразумевали именно такой режим работы: многие коммерческие СУБД содержат в своем составе приложения, позволяющие вводить и выполнять произвольные команды SQL. Команда, введенная пользователем, подлежит синтаксическому анализу, а затем система выбирает наиболее целесообразный способ ее выполнения.
Программа должна сообщить системе о том, что строку символов, введенную пользователем или полученную иным образом, следует считать, преобразовать в команду SQL, а затем выполнить. Подобные действия можно осуществить с помощью двух команд, рассмотренных ниже.
EXEC SQL PREPARE V FROM E, где V~ переменная SQL, a E — общая переменная или выражение строкового типа. Выражение Е считывается и анализируется (подготавливается — prepare), но не выполняется: найденный системой план (plan) выполнения присваивается переменной V.
exec SQL execute V. Содержимое переменной V трактуется как команда SQL и выполняется.
Обе стадии можно объединить в одну, если воспользоваться директивой
EXEC SQL EXECUTE IMMEDIATE Е
где Е, как и прежде, представляет общую переменную или выражение строкового типа. Недостаток такого подхода проявляется в тех ситуациях, когда выражение один раз "подготавливается", а затем многократно выполняется: при использовании инструкции execute immediate системе каждый раз приходится осуществлять подготовку одного и того же выражения к выполнению, а это обходится недешево — в том смысле, что требует немалых вычислительных затрат.