Внутренний язык СУБД. Сравнительные характеристики T-SQL и PL/SQL.
Введение
Практически каждая СУБД имеет в своем составе процедурное расширение языка SQL. Эти языки используются для реализации бизнес-логики и дополнительных проверок целостности на уровне сервера. Программные модули, написанные на этих языках, хранятся в СУБД и выполняются специальным компонентом непосредственно в ядре СУБД. Синтаксис таких языков разработан для максимально простой и удобной интеграции с SQL. Модули процедурного расширения SQL могут быть одного из следующих типов
- Хранимые процедуры, пакеты, функции
- Триггеры
- Безымянные блоки
Oracle. Процедурное расширение - PL/SQL. Синтаксис похож на ADA. Помимо СУБД, входит в другие продукты Oracle, например Oracle Developer. Является наиболее мощным из процедурных языков основных СУБД.
SQL Server. Процедурное расширение - Transact-SQL (T-SQL). Обладает основными возможностями. Дл версии 2005 отсутствовала обработка исключений.
Основные характеристики PL/SQL и T-SQL
- Полный диапазон типов данных
- Явно определяемая структура кода - блоки данных, процедуры и т.д.
- Операторы управления потоком команд - условные, циклы и т.д.
- Обработчики исключений
- Повторно используемые именованные блоки кода, такие как функции, процедуры, пакеты (только в PL/SQL)
- Тесная интеграция с SQL - непосредственный вызов команд SQL из процедурного кода
Блок PL/SQL. Структура
Вызов из sqlplus:
call dbms_output.put_line('aaa') exec dbms_output.put_line('aaa')
Структура блока plsql
declare i number; d date; begin i := 0; select count(*) into i from all_users; if i > 10 then dbms_output.put_line('> 10'); else dbms_output.put_line('<= 10'); end if; begin select sysdate into d from dual; exception when no_data_found then d := null; raise; end; end;
Основные элементы plsql
Комментарии
/* многострочные комментарии */
Идентификаторы
declare LongName number; begin longname := 10; dbms_output.put_line(LONGNAME); end; declare "LongName" number; begin longname := 10; dbms_output.put_line(LONGNAME); end; declare n_$# number; begin n_$# := 10; end;
Логический тип
declare b boolean; begin b := true; -- error -- dbms_output.put_line(b); dbms_output.put_line(case b when true then 1 else 0 end); if b then dbms_output.put_line(1); else dbms_output.put_line(0); end if; end;
Декларации
declare n1 number; n2 number := 10; n3 number default 10; n4 number not null := 30; begin dbms_output.put_line(nvl(n1, -100)); dbms_output.put_line(n2); dbms_output.put_line(n3); dbms_output.put_line(n4); end; declare n test.i%type; r test%rowtype; begin n := 10; dbms_output.put_line(n); select * into r from test where i = 1; dbms_output.put_line(r.i); dbms_output.put_line(r.s); end; -- видимость переменных declare a number := 10; b number := 20; begin dbms_output.put_line(a); dbms_output.put_line(b); declare a number; c number; begin a := 30; c := 40; dbms_output.put_line('---->'||a); dbms_output.put_line('---->'||b); dbms_output.put_line('---->'||c); end; dbms_output.put_line(a); dbms_output.put_line(b); end;
Именованные блоки
<<my_block>> declare a number := 10; b number := 20; begin dbms_output.put_line(a); dbms_output.put_line(b); declare a number; c number; begin a := 30; c := 40; dbms_output.put_line('---->'||my_block.a); dbms_output.put_line('---->'||a); dbms_output.put_line('---->'||b); dbms_output.put_line('---->'||c); end; dbms_output.put_line(a); dbms_output.put_line(b); end; <<my_block1>> declare a number := 10; begin dbms_output.put_line('my_block1 '||a); <<my_block2>> declare a number := 20; begin dbms_output.put_line('my_block2 '||my_block1.a); dbms_output.put_line('my_block2 '||a); <<my_block3>> declare a number := 30; begin dbms_output.put_line('my_block3 '||my_block1.a); dbms_output.put_line('my_block3 '||my_block2.a); dbms_output.put_line('my_block3 '||a); end; end; dbms_output.put_line('my_block1 '||a); end;
Управляющие конструкции
declare n number; begin n := 10; if n > 10 then n := 20; dbms_output.put_line(n); else n := 30; dbms_output.put_line(n); end if; if n > 10 then n := 20; dbms_output.put_line(n); end if; if n > 10 then n := 20; dbms_output.put_line(n); elsif n > 5 then n := 30; dbms_output.put_line(n); else n := 40; dbms_output.put_line(n); end if; case n when 10 then n := 100; dbms_output.put_line(n); when 12 then n := 200; dbms_output.put_line(n); else n := 300; dbms_output.put_line(n); end case; case when n = 10 then n := 100; dbms_output.put_line(n); when n = 12 then n := 200; dbms_output.put_line(n); else n := 300; dbms_output.put_line(n); end case; end; declare n number := 10; begin case n when 1 then dbms_output.put_line('1'); when 2 then dbms_output.put_line('1'); end case; exception when case_not_found then dbms_output.put_line('case not found'); end; declare n number; begin n := 1; loop dbms_output.put_line(n); n := n+1; exit when n > 10; end loop; end; declare n number; begin n := 1; loop dbms_output.put_line(n); n := n+1; if n > 10 then exit; end if; end loop; end; declare n number; begin n := 1; while n <= 10 loop dbms_output.put_line(n); n := n+1; end loop; end; declare n number; begin for n in 1..10 loop dbms_output.put_line(n); end loop; end; declare n number; begin for n in reverse 1..10 loop dbms_output.put_line(n); end loop; end;
Неявное использование переменной цикла
declare n number := 100; begin for n in 1..10 loop dbms_output.put_line(n); end loop; dbms_output.put_line('after ' || n); end; declare n number; begin for i in 1..10 loop n := i; dbms_output.put_line(n || ' ' || i); -- error -- i := 20; end loop; dbms_output.put_line(n); end;
Динамическое изменение границ
declare n number := 3; begin for i in 1..n loop if n < 10 then n := n+1; end if; dbms_output.put_line(i || ' ' || n); end loop; end;
Использование меток
begin <<l1>> for i in 1..3 loop for i in 5..6 loop dbms_output.put_line(l1.i || ' ' || i); end loop; end loop; end; begin <<l1>> for i in 1..3 loop for i in 5..6 loop dbms_output.put_line(l1.i || ' ' || i); exit l1 when i = 5; end loop; end loop; end; -- goto declare n number; begin if n = null then dbms_output.put_line('in if'); else goto met1; end if; dbms_output.put_line('after if'); <<met1>> dbms_output.put_line('after met1'); end; declare n number := 1; begin for i in 1..10 loop if i = 5 then goto cont; end if; n := n+1; dbms_output.put_line(n); <<cont>> null; end loop; end;
Основные объекты. Хранимые процедуры и функции
Хранимая процедура или функция - это подпрограмма, состоящая из SQL операторов и команд процедурного языка. Хранимая процедура и функция может:
- Содержать параметры (аргументы);
- Вызывать другие процедуры;
- Возвращать свой статус вызывающей процедуре или пакету, указывающий на успешное окончание или ошибку, и в случае ошибки на ее причину;
- Возвращать значения параметров вызывающей процедуре или пакету;
- Выполняется всегда на стороне сервера.
- Функция кроме того возвращает результат через свое имя.
Хранимые процедуры и функции значительно увеличивают мощность, эффективность и гибкость языка SQL и значительно ускоряют выполнение SQL-операторов и пакетов.
Хранимые процедуры создаются с помощью команды create procedure. Функции создаются с помощью команды - create function. Для выполнения хранимой процедуры, как системной, так и определенной пользователем, используется команда execute (выполнить). Можно также просто указать название хранимой процедуры, если оно является первым словом в операторе или пакете.
Хранимая процедура или функция имеет две части:
- Спецификация, которая объявляет процедуру или функцию и состоит из следующей информации:
- Имени процедуры
- Имен и типов данных аргументов, если есть
- Кроме этого, ТОЛЬКО для функций - типа данных возвращаемого значения
- Тело, которое определяет процедуру или функцию. Тело процедуры состоит из блока PL/SQL или T-SQL (который содержит предложения SQL и процедурного расширения).
Основные объекты. Триггеры
Триггер - это хранимая процедура специального вида, которая запускается при возникновении какого-либо события, обычно изменения данных в таблице. В частности, триггеры помогают сохранить ссылочную целостность данных пользователя, проверяя их согласованность в логически связанных таблицах. Основным достоинством триггеров является то, что они вызываются автоматически. Они будут работать независимо от причины, которая вызвала модификацию данных, как, например, после ввода данных клерком, так и при выполнении некоторой прикладной процедуры. Триггер может быть связан с одним или несколькими операторами модификации, такими как update, insert или delete.