Опубликован: 25.11.2008 | Доступ: свободный | Студентов: 4417 / 650 | Оценка: 4.46 / 4.18 | Длительность: 26:08:00
Лекция 12:

Встроенный SQL

Аннотация: Лекция посвящена описанию дополнительных возможностей языка SQL, используемых при разработке хранимых процедур и приложений. Рассматриваются порядок трансляции и выполнения запросов SQL
Ключевые слова: SQL, доступ, БД, ПО, операторы, анализ, COBOL, PL/1, Pascal, стоимость, оптимизация запросов, затраты, СУБД, встроенный SQL, интерактивный SQL, встраивания, консоль, запрос, список, таблица, server, специальный символ, транслятор, локальная переменная, входной, значение, переменная, DECLARE CURSOR, относительная адресация, объявление курсора, SQL2, открытие курсора, Prior, подзапрос, закрытие курсора, прокручиваемый курсор, deallocation, разделяемая память, позиционный оператор, последовательный курсор, stored procedures, выходные параметры, Oracle, Java, хранимая процедура, оптимальный план, создание хранимой процедуры, права, запуск, ключевое слово, vary, recompilation, исполнение, план исполнения, параметр, авторское право, администратор БД, функция, объект, место, удаление хранимой процедуры, поле, тип данных, согласование типов, операции, базы данных, выходной параметр, приложение, сервер, триггер, тип триггера, семантическая целостность, referential integrity, создание триггера, команда, REVOKE, статический SQL, информация, время выполнения, план выполнения, динамический SQL, синтаксис, базовая, оптимизация, идентификатор, дескриптор, программное обеспечение

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

Эта двойственность SQL создает ряд преимуществ:

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

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

Базовыми языками программирования могут быть языки C, COBOL, PL/1, Pascal.

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

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

Процесс выполнения операторов SQL может быть условно разделен на 5 этапов (см. рис. 12.1).

Процесс выполнения операторов SQL

Рис. 12.1. Процесс выполнения операторов SQL
  1. На первом этапе выполняется синтаксический анализ оператора SQL. На этом этапе проверяется корректность записи SQL-оператора в соответствии с правилами синтаксиса.
  2. На этом этапе проверяется корректность параметров оператора SQL: имен отношений, имен полей данных, привилегий пользователя по работе с указанными объектами. Здесь обнаруживаются семантические ошибки.
  3. На этом этапе проводится оптимизация запроса. СУБД проводит разделение целостного запроса на ряд минимальных операций и оптимизирует последовательность их выполнения с точки зрения стоимости выполнения запроса. На этом этапе строится несколько планов выполнения запроса и выбирается из них один — оптимальный для данного состояния БД.
  4. На четвертом этапе СУБД генерирует двоичную версию оптимального плана запроса, подготовленного на этапе 3. Двоичный план выполнения запроса в СУБД фактически является эквивалентом объектного кода программы.
  5. И наконец, только на пятом этапе СУБД реализует (выполняет) разработанный план, тем самым выполняя оператор SQL.

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

Этапы выполнения операторов SQL одни и те же как в интерактивном режиме, так и внутри приложений. Однако при работе с готовым приложением многие этапы СУБД может выполнить заранее.

Особенности встроенного SQL

При объединении операторов SQL c базовым языком программирования должны соблюдаться следующие принципы:

  1. Операторы SQL включаются непосредственно в текст программы на исходном языке программирования. Исходная программа поступает на вход препроцессора SQL, который компилирует операторы SQL.
  2. Встроенные операторы SQL могут ссылаться на переменные базового языка программирования.
  3. Встроенные операторы SQL получают результаты SQL-запросов с помощью переменных базового языка программирования.
  4. Для присвоения неопределенных значений ( NULL ) атрибутам отношений БД используются специальные функции.
  5. Для обеспечения построчной обработки результатов запросов во встроенный SQL добавляются несколько новых операторов, которые отсутствуют в интерактивном SQL.

Операторы манипулирования данными не требуют изменения для их встраивания в программный SQL. Однако оператор поиска ( SELECT ) потребовал изменений.

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

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

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

SELECT [{ALL | DISTINCT}] 
<список возвращаемых столбцов> 
INTO <список переменных базового языка> 
FROM <список исходных таблиц> 
[WHERE <условия соединения и поиска>]

Мы видим, что во встроенный SELECT добавился новый для нас раздел, содержащий список переменных базового языка. Именно в эти переменные будет помещен результат однострочного запроса, поэтому список переменных базового языка должен быть согласован как по порядку, так и по типу и размеру данных со списком возвращаемых столбцов. По правилам любого языка программирования все базовые переменные предварительно описаны в прикладной программе. Например, если в нашей БД "Библиотека" существует таблица READERS (Читатели), мы можем получить сведения о конкретном читателе.

CREATE TABLE READERS 
(
READER_ID Smallint(4) PRIMARY KEY,
FIRST_NAME char(30) NOT NULL,
LAST_NAME char(30) NOT NULL,
ADRES char(50) ,
HOME_PHON char(12) ,
WORK_PHON char(12) ,
BIRTH_DAY date CHECK( DateDiff(year, GetDate(),
BIRTH_DAY) >=17 )
);

Для этого опишем базовые переменные. Рассмотрим пример для MS SQL SERVER 7.0, используя язык Transact SQL. При описании локальных переменных в языке Transact SQL используется специальный символ @. Комментарии в Transact SQL заключены в парные символы /* комментарий */.

DECLARE @READER_ID int
DECLARE @FIRS_NAME Char(30), @LAST_NAME Char(30), @ADRES Char(50)
DECLARE @HOME_PHON Char(12),@WORK_PHON Char(12) 
/* зададим уникальный номер читательского билета */
SET @READER_ID = 4
/* теперь выполним запрос и поместим полученные сведения в определенные
ранее переменные */ 
SELECT READERS.FIRST_NAME, READERS.LAST_NAME, 
       READERS.ADRES, READERS.HOME_PHON, 
       READERS.WORK_PHON 
INTO @FIRS_NAME, @LAST_NAME, @ADRES, 
     @HOME_PHON,@WORK_PHON 
FROM READERS WHERE READERS.READER_ID = @READER_ID

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

В нашем примере базовые переменные играют разную роль. Локальная переменная @READER_ID является входной по отношению к запросу. Ей присвоено значение 4, и в запросе это значение используется для фильтрации данных, поэтому эта переменная используется в условии WHERE.

Остальные базовые переменные играют роль выходных переменных, в них СУБД помещает результат выполнения запроса, помещая в них значения соответствующих полей отношения READERS, извлеченные из БД.

Михаил Дубовик
Михаил Дубовик

В лекции как пример отношения в третьей нормальной форме приводится такая схема: (Номер зач. кн.\ ФИО \ Специальность \ Группа). Первичный ключ - Номер зач. кн. Но ведь существует следующая транзитивная зависимость: 

Номер зач. кн. -> Группа -> Специальность.

Получается, что отношение все же еще во второй нормальной форме. Или в моих рассуждениях ошибка?

Михаил Скок
Михаил Скок
Евгений Шаров
Евгений Шаров
Россия, Североморск, школа№11, 1991
Виктория Кадраева
Виктория Кадраева
Россия, г. Уфа