Внутренний язык СУБД. Сравнительные характеристики 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.