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


