Внутренний язык СУБД. Сравнительные характеристики T-SQL и PL/SQL.

Введение

Практически каждая СУБД имеет в своем составе процедурное расширение языка SQL. Эти языки используются для реализации бизнес-логики и дополнительных проверок целостности на уровне сервера. Программные модули, написанные на этих языках, хранятся в СУБД и выполняются специальным компонентом непосредственно в ядре СУБД. Синтаксис таких языков разработан для максимально простой и удобной интеграции с SQL. Модули процедурного расширения SQL могут быть одного из следующих типов

  1. Хранимые процедуры, пакеты, функции
  2. Триггеры
  3. Безымянные блоки

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.

  • Нет меток