Распределенные базы и хранилища данных

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

    Практические занятия

    Постановка задачи. Проектирование данных на концептуальном и логическом уровнях. Нормализация отношений.

    Презентация по ER-моделированию

    ER нотации

    Пример модели в ERwin

    Подготовка SQL скриптов генерации схемы отношений БД в ERwin. Разработка скрипта для ввода тестовой информации.

    Видео-презентация (Для проигрывания требуется Windows Media Player)

    Архитектура MS SQL Server 2005. Настройка и использование основных компонент среды. Создание учебной базы данных.

    Видео-презентация (Для проигрывания требуется Windows Media Player)

    Работа с СУБД MS SQL Server 2005, ORACLE 10g. Примеры соединений с БД, технологии разработки клиенского приложения

    Использование технологии Java Database Connectivity (JDBC) для работы с базами данных

    Презентация

    Примеры к презентации

    SQL-скрипты, проект и исходные коды

    package org.mai806.jdbcsample;
    
    import java.sql.*;
    
    public class QuerySample {
        
        public static void main(String[] args) throws Exception {
            
            /* ======== Подключение к MS SQL Server ===== */
            // Загрузка драйвера
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            // Соединение с базой данных
            Connection connection = DriverManager.getConnection(
                    "jdbc:sqlserver://localhost:1433;databaseName=o01;", 
                    // localhost - сервер СУБД, o01 - имя базы данных
                    "sa", "123"); // пользователь, пароль
            
            /* ======== Подключение к Oracle ============
            // Загрузка драйвера
            Class.forName("oracle.jdbc.OracleDriver");
            // Соединение с базой данных
            Connection connection = DriverManager.getConnection(
                            "jdbc:oracle:thin:@localhost:1521:orcl", 
                            // localhost - сервер СУБД, orcl - SID базы оракла
                            "o01", "o01"); // пользователь, пароль         
            
            // Создание Statement
            PreparedStatement stmt = connection.prepareStatement
            ("select ID, NAME from PERSON where NAME like ?");
            stmt.setString(1, "%S%");
            // Выполнение запроса
            ResultSet rs = stmt.executeQuery();
            // Перебор результата выполнения запроса
            while(rs.next()) {
                // Пример выбора параметра по номеру или по имени
                System.out.println("ID: " +
                        rs.getLong(1) + "; NAME="+
                        rs.getString("NAME"));
            }
            
            // закрытие использованных ресурсов БД
            rs.close();
            stmt.close();
            connection.close();
        }
    }
    package org.mai806.jdbcsample;
    
    import java.sql.*;
    import java.util.ResourceBundle;
    
    public class StoredProcedureSample {
        
        private static Connection connection = null;
        public static void main(String[] args) throws Exception {
            // Получение соединения из значений параметров в файле properties
            ResourceBundle properties = ResourceBundle.getBundle("database");
            Class.forName(properties.getString("driver"));
            connection = DriverManager.getConnection(
                    properties.getString("url"),
                    properties.getString("user"),
                    properties.getString("password"));
            
            transferAmount(1,2,100.0);
            connection.close();
        }
        
        /**
         * Переводит указанную сумму с одного счета на другой
         * @param from счет плательщика
         * @param to счет получателя
         * @param amount сумма
         */
        public static void transferAmount(long from, long to, double amount)
        throws Exception {
            // Создание Statement
            CallableStatement stmt
                    = connection.prepareCall("{call TransferAmount(?,?,?)}");
            // Установка параметров
            stmt.setLong(1, from);
            stmt.setLong(2, to);
            stmt.setDouble(3, amount);
            // Выполнение процедуры
            stmt.execute(); 
        }
    }
    package org.mai806.jdbcsample;
    
    import java.sql.*;
    import java.util.ResourceBundle;
    
    public class TransactionalSample {
        
        private static Connection connection = null;
        public static void main(String[] args) throws Exception {
            
            // Получение соединения из значений параметров в файле properties
            ResourceBundle properties = ResourceBundle.getBundle("database");
            Class.forName(properties.getString("driver"));
            connection = DriverManager.getConnection(
                    properties.getString("url"),
                    properties.getString("user"),
                    properties.getString("password"));
            
            // Ручное управление транзакциями
            connection.setAutoCommit(false);
            
            try {
                transferAmount(2, 1, 10.0);
            } finally {
                connection.close();
            }
        }
        
        /**
         * Переводит указанную сумму с одного счета на другой
         * @param from счет плательщика
         * @param to счет получателя
         * @param amount сумма
         */
        public static void transferAmount(long from, long to,
                double amount) throws Exception {
            PreparedStatement stmt = null;
            Statement query = null;
            try {
                stmt = connection.prepareStatement
                ("update ACCOUNT set AMOUNT=AMOUNT+? where ID=?");
                // Забираем сумму со счета плательщика
                stmt.setDouble(1, -amount);
                stmt.setLong(2, from);
                stmt.execute();
                
                // Добавляем сумму на счет получателя
                stmt.setDouble(1, amount);
                stmt.setLong(2, to);
                stmt.execute();
                
                // Пост-проверка: отрицательность счета плательщика
                query = connection.createStatement();
                ResultSet rs = query.executeQuery(
                        "select AMOUNT from ACCOUNT where ID="+from+" and AMOUNT<0");
                if (rs.next()) {
                    throw new Exception("На счете №"+from+" 
                    недосточно средств ["+(amount+rs.getDouble(1))+"] 
                    для снятия суммы ["+amount+"]");
                }
                connection.commit();
                System.out.println("Перечисление средств успешно выполнено");
            } catch(Exception e) {
                e.printStackTrace();
                connection.rollback();
            } finally {
                if (stmt!=null)
                    stmt.close();
                if (query!=null)
                    query.close();
            }
        }
        
    }

    Работа с базами данных из J2EE Web-контейнера

    Презентация

    Объектно-реляционное отображения для работы с базами данных

    Презентация

    Использование препроцессора для работы с API СУБД

    Презентация

    Страницы:

    Введение

    Практически каждая СУБД имеет в своем составе процедурное расширение языка 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.

    Практические занятия

    Постановка задачи. Проектирование данных на концептуальном и логическом уровнях. Нормализация отношений.

    Презентация по ER-моделированию

    ER нотации

    Пример модели в ERwin

    Подготовка SQL скриптов генерации схемы отношений БД в ERwin. Разработка скрипта для ввода тестовой информации.

    Видео-презентация (Для проигрывания требуется Windows Media Player)

    Архитектура MS SQL Server 2005. Настройка и использование основных компонент среды. Создание учебной базы данных.

    Видео-презентация (Для проигрывания требуется Windows Media Player)

    Работа с СУБД MS SQL Server 2005, ORACLE 10g. Примеры соединений с БД, технологии разработки клиенского приложения

    Использование технологии Java Database Connectivity (JDBC) для работы с базами данных

    Презентация

    Примеры к презентации

    SQL-скрипты, проект и исходные коды

    package org.mai806.jdbcsample;
    
    import java.sql.*;
    
    public class QuerySample {
        
        public static void main(String[] args) throws Exception {
            
            /* ======== Подключение к MS SQL Server ===== */
            // Загрузка драйвера
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            // Соединение с базой данных
            Connection connection = DriverManager.getConnection(
                    "jdbc:sqlserver://localhost:1433;databaseName=o01;", 
                    // localhost - сервер СУБД, o01 - имя базы данных
                    "sa", "123"); // пользователь, пароль
            
            /* ======== Подключение к Oracle ============
            // Загрузка драйвера
            Class.forName("oracle.jdbc.OracleDriver");
            // Соединение с базой данных
            Connection connection = DriverManager.getConnection(
                            "jdbc:oracle:thin:@localhost:1521:orcl", 
                            // localhost - сервер СУБД, orcl - SID базы оракла
                            "o01", "o01"); // пользователь, пароль         
            
            // Создание Statement
            PreparedStatement stmt = connection.prepareStatement
            ("select ID, NAME from PERSON where NAME like ?");
            stmt.setString(1, "%S%");
            // Выполнение запроса
            ResultSet rs = stmt.executeQuery();
            // Перебор результата выполнения запроса
            while(rs.next()) {
                // Пример выбора параметра по номеру или по имени
                System.out.println("ID: " +
                        rs.getLong(1) + "; NAME="+
                        rs.getString("NAME"));
            }
            
            // закрытие использованных ресурсов БД
            rs.close();
            stmt.close();
            connection.close();
        }
    }
    package org.mai806.jdbcsample;
    
    import java.sql.*;
    import java.util.ResourceBundle;
    
    public class StoredProcedureSample {
        
        private static Connection connection = null;
        public static void main(String[] args) throws Exception {
            // Получение соединения из значений параметров в файле properties
            ResourceBundle properties = ResourceBundle.getBundle("database");
            Class.forName(properties.getString("driver"));
            connection = DriverManager.getConnection(
                    properties.getString("url"),
                    properties.getString("user"),
                    properties.getString("password"));
            
            transferAmount(1,2,100.0);
            connection.close();
        }
        
        /**
         * Переводит указанную сумму с одного счета на другой
         * @param from счет плательщика
         * @param to счет получателя
         * @param amount сумма
         */
        public static void transferAmount(long from, long to, double amount)
        throws Exception {
            // Создание Statement
            CallableStatement stmt
                    = connection.prepareCall("{call TransferAmount(?,?,?)}");
            // Установка параметров
            stmt.setLong(1, from);
            stmt.setLong(2, to);
            stmt.setDouble(3, amount);
            // Выполнение процедуры
            stmt.execute(); 
        }
    }
    package org.mai806.jdbcsample;
    
    import java.sql.*;
    import java.util.ResourceBundle;
    
    public class TransactionalSample {
        
        private static Connection connection = null;
        public static void main(String[] args) throws Exception {
            
            // Получение соединения из значений параметров в файле properties
            ResourceBundle properties = ResourceBundle.getBundle("database");
            Class.forName(properties.getString("driver"));
            connection = DriverManager.getConnection(
                    properties.getString("url"),
                    properties.getString("user"),
                    properties.getString("password"));
            
            // Ручное управление транзакциями
            connection.setAutoCommit(false);
            
            try {
                transferAmount(2, 1, 10.0);
            } finally {
                connection.close();
            }
        }
        
        /**
         * Переводит указанную сумму с одного счета на другой
         * @param from счет плательщика
         * @param to счет получателя
         * @param amount сумма
         */
        public static void transferAmount(long from, long to,
                double amount) throws Exception {
            PreparedStatement stmt = null;
            Statement query = null;
            try {
                stmt = connection.prepareStatement
                ("update ACCOUNT set AMOUNT=AMOUNT+? where ID=?");
                // Забираем сумму со счета плательщика
                stmt.setDouble(1, -amount);
                stmt.setLong(2, from);
                stmt.execute();
                
                // Добавляем сумму на счет получателя
                stmt.setDouble(1, amount);
                stmt.setLong(2, to);
                stmt.execute();
                
                // Пост-проверка: отрицательность счета плательщика
                query = connection.createStatement();
                ResultSet rs = query.executeQuery(
                        "select AMOUNT from ACCOUNT where ID="+from+" and AMOUNT<0");
                if (rs.next()) {
                    throw new Exception("На счете №"+from+" 
                    недосточно средств ["+(amount+rs.getDouble(1))+"] 
                    для снятия суммы ["+amount+"]");
                }
                connection.commit();
                System.out.println("Перечисление средств успешно выполнено");
            } catch(Exception e) {
                e.printStackTrace();
                connection.rollback();
            } finally {
                if (stmt!=null)
                    stmt.close();
                if (query!=null)
                    query.close();
            }
        }
        
    }

    Работа с базами данных из J2EE Web-контейнера

    Презентация

    Объектно-реляционное отображения для работы с базами данных

    Презентация

    Использование препроцессора для работы с API СУБД

    Презентация

    Вернуться к учебному плану