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

Хранимые процедуры и функции. Типы параметров, синтаксис описания формальных параметров

Разбить на страницы
Показывать лекцию целиком

SQL Server

Хранимая процедура - это подпрограмма, состоящая из SQL операторов и команд T-SQL. Хранимая процедура сохраняется на сервере и выполняется по команде пользователя или вызывается из блока T-SQL. План выполнения процедуры подготавливается во время запуска процедуры, поэтому собственно выполнение процедуры происходит очень быстро. Хранимая процедура может:

  • Содержать параметры (аргументы);
  • Вызывать другие процедуры;
  • Возвращать свой статус вызывающей процедуре или модулю T_SQL, указывающий на успешное окончание или ошибку, и в случае ошибки на ее причину;
  • Возвращать значения параметров вызывающей процедуре или модулю T-SQL ;
  • Синтаксис для создания хранимой процедуры:

    create procedure [владелец.]название_процедуры[;номер] [
    [(] @название_параметра тип_данных [= default] [output]
    [,  @название_параметра тип_данных [= default] [output]]...[)]] [with
    recompile]
    as sql_операторы

    Оператор execute:

    [execute] [@return_status =]
    	[[[сервер.]база_данных.]владелец.]название_процедуры[;номер]
    		[[@название_параметра = ] значение | 
    		 [@название_параметра = ] @переменная [output]
    [,[@название_параметра = ] значение | 
    	 [@название_параметра = ] @переменная [output]...]]
    [with recompile]

    Параметры

    Параметр - это аргумент хранимой процедуры. Один или несколько параметров могут быть объявлены в операторе создания процедуры. Значение каждого параметра, объявленного в операторе create procedure, должно указываться пользователем в момент вызова процедуры.

    Названиям параметров должен предшествовать символ "@", а сами эти названия должны соответствовать правилам, установленным для идентификаторов. Для всех параметров должен быть указан системный или пользовательский тип данных, и если необходимо длина этого типа данных. Названия параметров являются локальными по отношению к содержащей их процедуре; такие же названия можно использовать для параметров в другой процедуре.

    В операторе create procedure для параметра можно указать значение, принимаемое по умолчанию. Это значение, которое может быть любой константой, используется в качестве аргумента процедуры, если для этого параметра не было указано никакого значения.

    CREATE   proc  dbo.tran_Begin /*
     * Инициализация транзакции
     * Если процедура выполняется внутри транзакции, то создается savepoint
     * Иначе инициализируется транзакция
     * На выходе передается null для транзакции и имя точки сохранения для savepoint
     */
    (@trName DObjectName output, @explicitSavepointNameFlag DLogical = 0)
    as
    	declare @d Datetime
    begin
    --	return 0
    
    	if @@trancount = 0
    	begin
    		select @trName = null
    		begin transaction
    	end
    	else
    	begin
    -- если не задано имя и не установлен флаг использования переданного имени, то генерим имя
    		if @explicitSavepointNameFlag = 0 or @trName is null
    		begin
    			select @d = getdate()
    			select @trName = 'tr_'+ISNULL(convert(varchar, @@nestlevel), '')+'_'+ISNULL(convert(varchar(50),
    				rand(datepart(mm, @d)*100000+datepart(ss, @d)*1000+datepart(ms, @d))), '')
    		end
    		save tran @trName
    	end
    
    	if @@error <> 0
    	begin
    -- ошибка создания транзакции
    		return 5
    	end
    
    	return 0
    end
    
    CREATE  proc  dbo.tran_Commit /*
     * Подтверждение транзакции
     * Работает в паре с tran_Begin
     * на вход передается имя точки сохранения (транзакции), возвращенное tran_Begin
     * Если вызов идет из транзакции и @trName равно null, то выполняется commit,
     * иначе ничего не делается
     */
    (@trName DObjectName)
    as
    begin
    	if @@trancount > 0 and @trName is null
    	begin
    		commit
    
    		if @@error <> 0
    		begin
    -- ошибка подтверждения транзакции
    			return 6
    		end
    	end
    
    	return 0
    end
    
    CREATE  proc  dbo.tran_Rollback /*
     * Откат транзакции
     * Работает в паре с tran_Begin
     * на вход передается имя точки сохранения (транзакции), возвращенное tran_Begin
     * Если вызов идет из транзакции и @trName равно null, то выполняется откат всей транзакции,
     * иначе выполняется откат до точки сохранения @trName
     */
    (@trName DObjectName)
    as
    begin
    	if @@trancount > 0
    	begin
    		if @trName is null
    			rollback tran
    		else
    			rollback tran @trName
    
    		if @@error <> 0
    		begin
    -- ошибка отката транзакции
    			return 7
    		end
    	end
    
    	return 0
    end

    Возврат результатов

    Хранимые процедуры сообщают свой "статус возврата", который указывает, была ли выполнена процедура полностью, или нет, а также причины неудачи. Это значение может храниться в переменной, которая передается процедуре при ее вызове, и использоваться в последующих операторах Transact-SQL. Другой способ возврата информации из хранимых процедур состоит в возврате значений через выходные параметры. Параметры, определенные как выходные, в операторе create procedure (создать процедуру) или execute (выполнить) используются для возврата значений в место вызова процедуры. Затем с помощью условных операторов можно проверить возвращаемое значение.

    Код возврата и выходные параметры позволяют разделить хранимые процедуры на модули. Группа SQL операторов, которые используются несколькими хранимыми процедурами, могут быть объединены в одну процедуру, которая сообщает свой статус выполнения или значения своих параметров вызывающей процедуре. Например, многие системные процедуры, поставляемые с SQL Сервером, обращаются к процедуре, которая проверяет являются ли указанные параметры правильными идентификаторами.

    Если в операторах create procedure и execute указывается опция output в названии параметра, то процедура возвращает значение этого параметра вызывающему объекту. Этим объектом может быть SQL пакет или другая хранимая процедура, которые используют возвращаемые значения в своей дальнейшей работе. Если возвращаемые параметры используются в операторе execute, который является частью пакета, то значения возвращаемых параметров вместе с заголовком выводятся на экран перед выполнением последующих операторов пакета.

    declare @tranName DObjectName
    declare @retCode integer
    begin
    
    	execute tran_Begin @tranName output
    
    select @tranName
    .........................................

    Oracle

    Создание процедур

    create or replace procedure my_proc(i in number := 123,
       j out number, k in out number /* error := 123 */)
    as
    begin
        dbms_output.put_line('i = ' || i);
        dbms_output.put_line('j = ' || j);
        dbms_output.put_line('k = ' || k);
    
        if i is null then
            return;
        end if;
    
    -- error
    --    i := 10;
        j := 20;
        k := 30;
    end;
    
    create or replace procedure my_proc_error
      (i number /* error (1) */, s varchar2 /* error (10) */)
    as
    begin
        null;
    end;
    
    declare
        a number;
        b number;
        c number;
    begin
        a := 1;
        b := 2;
        c := 3;
        my_proc(a, b, c);
    
        dbms_output.put_line('a = ' || a);
        dbms_output.put_line('b = ' || b);
        dbms_output.put_line('c = ' || c);
    end;

    Создание функций

    create or replace function my_fun(i in number) return number
    as
        j number;
    begin
        j := i+10;
        return j;    
    end;
        
    declare
        a number;
    begin
        a := 12+my_fun(10);
        dbms_output.put_line('a = ' || a);
    end;
    
    create or replace function my_fun(i in number) return number
    as
        j number;
    
        procedure p(n in out number)
        as
        begin
            n := n+i+j;        
        end;
    begin
        j := 3;
        p(j);
        j := j+i+10;
        return j;    
    end;
        
    declare
        a number;
    begin
        a := 12+my_fun(10);
        dbms_output.put_line('a = ' || a);
    end;

    Вызов процедур и функций

    create or replace procedure my_p
     (s varchar2, i number := 10, j number := 20)
    as
    begin
        null;
    end;
    
    declare
        a number;
        b number;
        s varchar2(100);
    begin
        my_p(s);
        my_p(s, a);
        my_p(s, a, b);
        my_p(s=>s, j=>b);
        my_p(s, j=>b);
    end;

    Передача параметров. Атрибут NOCOPY

    create or replace procedure my_p2
     (s1 out varchar2, s2 in out nocopy varchar2)
    as
    begin
        s1 := 'aaaaaaaaaaaaaaaaaaaaaaaaaa';
        s2 := 'bbbbbbbbbbbbbbbbbbbbbbbbbb';
    end;

    Модули PL/SQL

    create or replace package PackageTest
    as
        type point is record
            (
                x number,
                y number
             );
    
        tpoint point;
        n number;
             
        procedure p(ii in number, ss out varchar2);
        function f(n in point) return number;
        function f(x in number, y in number) return number;
    end PackageTest;
    
    create or replace package body PackageTest
    as
        type t1 is record
            (
                i number,
                j number
             );
    
        cnt number;
        trow1 test%rowtype;
         
        procedure p(ii in number, ss out varchar2)
        is
        begin
            select s into ss from test where i = ii;
        exception
            when no_data_found then
                ss := 'empty string';
        end;
    
        function f(n in point) return number
        as
        begin
            return n.x+n.y;
        end;
    
        function f(x in number, y in number) return number
        as
        begin
            return x+y;
        end;
    begin
        trow1.i := 1;
        trow1.s := 'null string';
        n := 100;
        cnt := -10;
    end PackageTest;
    
    create or replace procedure PackageTest_test
    as
    -- error
    --    d1 PackageTest.tl;
        s varchar2(100);
        n PackageTest.point;
    begin
        n.x := 100;
        n.y := 200;
        PackageTest.p(1, s);
        dbms_output.put_line('s = ' || s);
        dbms_output.put_line('f((100, 100)) = ' || PackageTest.f(n));
        dbms_output.put_line('f(100, 100) = ' || PackageTest.f(n));
        dbms_output.put_line('n = ' || PackageTest.n);
    -- error
    --    dbms_output.put_line('cnt = ' || PackageTest.cnt);
    end;

    Просмотр объектов и компиляция

    desc user_objects
    
    select object_name, object_type, status from user_objects;

    Перекомпиляция процедур и функций

    create or replace function f(i in number)
    return varchar2
    as
    begin
        return to_char(i+1);
    end;
    
    create or replace procedure p(ii in number, ss out varchar2)
    as
    begin
        select s into ss from test where i = ii;
    exception
        when no_data_found then
            ss := 'no data';
    end;
    
    select substr(object_name, 1, 30), object_type, 
      status from user_objects;
    
    select substr(object_name, 1, 30), object_type, 
         status from user_objects where object_type in 
                 ('PROCEDURE', 'FUNCTION', 'PACKAGE', 
                   'PACKAGE BODY') and (object_name like 'P%' 
                     or object_name like 'F%');
    
    declare
        i number;
        s varchar2(100);
    begin
        i := 10;
        s := f(i);
        dbms_output.put_line(s);
    
        i := 1;
        p(i, s);
        dbms_output.put_line(s);
    end;
    
    alter table test add h date;
    alter table test drop column h;
    
    alter procedure p compile;
    
    select * from user_errors;
    
    alter function f compile;
    
    alter package packagetest compile specification;
    alter package packagetest compile body;
    alter package packagetest compile package;
    
    select substr(object_name, 1, 30), object_type, 
         status from user_objects where object_type in 
                 ('PROCEDURE', 'FUNCTION', 'PACKAGE', 
                    'PACKAGE BODY') and (object_name like 'P%'
                       or object_name like 'F%');
    
    select * from user_errors;

    Скрипт для перекомпиляции процедур и функций

    Необходимо поместить в файл, запуск @<file>.sql

    ----------------------------------------------------
    set echo off
    set linesize 1000
    set pagesize 500
    set heading off
    set feedback off
    spool c:\tmp\a.sql
    select 'ALTER ' || object_type || ' ' || object_name || ' COMPILE;
      ' from user_objects where object_type in 
            ('PROCEDURE', 'FUNCTION', 'PACKAGE');
    select 'SELECT * FROM USER_ERRORS;' from dual;
    spool off
    @c:\tmp\a.sql
    host del c:\tmp\a.sql
    -----------------------------------------------------

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

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

    Презентация по 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 Server

    Хранимая процедура - это подпрограмма, состоящая из SQL операторов и команд T-SQL. Хранимая процедура сохраняется на сервере и выполняется по команде пользователя или вызывается из блока T-SQL. План выполнения процедуры подготавливается во время запуска процедуры, поэтому собственно выполнение процедуры происходит очень быстро. Хранимая процедура может:

  • Содержать параметры (аргументы);
  • Вызывать другие процедуры;
  • Возвращать свой статус вызывающей процедуре или модулю T_SQL, указывающий на успешное окончание или ошибку, и в случае ошибки на ее причину;
  • Возвращать значения параметров вызывающей процедуре или модулю T-SQL ;
  • Синтаксис для создания хранимой процедуры:

    create procedure [владелец.]название_процедуры[;номер] [
    [(] @название_параметра тип_данных [= default] [output]
    [,  @название_параметра тип_данных [= default] [output]]...[)]] [with
    recompile]
    as sql_операторы

    Оператор execute:

    [execute] [@return_status =]
    	[[[сервер.]база_данных.]владелец.]название_процедуры[;номер]
    		[[@название_параметра = ] значение | 
    		 [@название_параметра = ] @переменная [output]
    [,[@название_параметра = ] значение | 
    	 [@название_параметра = ] @переменная [output]...]]
    [with recompile]

    Параметры

    Параметр - это аргумент хранимой процедуры. Один или несколько параметров могут быть объявлены в операторе создания процедуры. Значение каждого параметра, объявленного в операторе create procedure, должно указываться пользователем в момент вызова процедуры.

    Названиям параметров должен предшествовать символ "@", а сами эти названия должны соответствовать правилам, установленным для идентификаторов. Для всех параметров должен быть указан системный или пользовательский тип данных, и если необходимо длина этого типа данных. Названия параметров являются локальными по отношению к содержащей их процедуре; такие же названия можно использовать для параметров в другой процедуре.

    В операторе create procedure для параметра можно указать значение, принимаемое по умолчанию. Это значение, которое может быть любой константой, используется в качестве аргумента процедуры, если для этого параметра не было указано никакого значения.

    CREATE   proc  dbo.tran_Begin /*
     * Инициализация транзакции
     * Если процедура выполняется внутри транзакции, то создается savepoint
     * Иначе инициализируется транзакция
     * На выходе передается null для транзакции и имя точки сохранения для savepoint
     */
    (@trName DObjectName output, @explicitSavepointNameFlag DLogical = 0)
    as
    	declare @d Datetime
    begin
    --	return 0
    
    	if @@trancount = 0
    	begin
    		select @trName = null
    		begin transaction
    	end
    	else
    	begin
    -- если не задано имя и не установлен флаг использования переданного имени, то генерим имя
    		if @explicitSavepointNameFlag = 0 or @trName is null
    		begin
    			select @d = getdate()
    			select @trName = 'tr_'+ISNULL(convert(varchar, @@nestlevel), '')+'_'+ISNULL(convert(varchar(50),
    				rand(datepart(mm, @d)*100000+datepart(ss, @d)*1000+datepart(ms, @d))), '')
    		end
    		save tran @trName
    	end
    
    	if @@error <> 0
    	begin
    -- ошибка создания транзакции
    		return 5
    	end
    
    	return 0
    end
    
    CREATE  proc  dbo.tran_Commit /*
     * Подтверждение транзакции
     * Работает в паре с tran_Begin
     * на вход передается имя точки сохранения (транзакции), возвращенное tran_Begin
     * Если вызов идет из транзакции и @trName равно null, то выполняется commit,
     * иначе ничего не делается
     */
    (@trName DObjectName)
    as
    begin
    	if @@trancount > 0 and @trName is null
    	begin
    		commit
    
    		if @@error <> 0
    		begin
    -- ошибка подтверждения транзакции
    			return 6
    		end
    	end
    
    	return 0
    end
    
    CREATE  proc  dbo.tran_Rollback /*
     * Откат транзакции
     * Работает в паре с tran_Begin
     * на вход передается имя точки сохранения (транзакции), возвращенное tran_Begin
     * Если вызов идет из транзакции и @trName равно null, то выполняется откат всей транзакции,
     * иначе выполняется откат до точки сохранения @trName
     */
    (@trName DObjectName)
    as
    begin
    	if @@trancount > 0
    	begin
    		if @trName is null
    			rollback tran
    		else
    			rollback tran @trName
    
    		if @@error <> 0
    		begin
    -- ошибка отката транзакции
    			return 7
    		end
    	end
    
    	return 0
    end

    Возврат результатов

    Хранимые процедуры сообщают свой "статус возврата", который указывает, была ли выполнена процедура полностью, или нет, а также причины неудачи. Это значение может храниться в переменной, которая передается процедуре при ее вызове, и использоваться в последующих операторах Transact-SQL. Другой способ возврата информации из хранимых процедур состоит в возврате значений через выходные параметры. Параметры, определенные как выходные, в операторе create procedure (создать процедуру) или execute (выполнить) используются для возврата значений в место вызова процедуры. Затем с помощью условных операторов можно проверить возвращаемое значение.

    Код возврата и выходные параметры позволяют разделить хранимые процедуры на модули. Группа SQL операторов, которые используются несколькими хранимыми процедурами, могут быть объединены в одну процедуру, которая сообщает свой статус выполнения или значения своих параметров вызывающей процедуре. Например, многие системные процедуры, поставляемые с SQL Сервером, обращаются к процедуре, которая проверяет являются ли указанные параметры правильными идентификаторами.

    Если в операторах create procedure и execute указывается опция output в названии параметра, то процедура возвращает значение этого параметра вызывающему объекту. Этим объектом может быть SQL пакет или другая хранимая процедура, которые используют возвращаемые значения в своей дальнейшей работе. Если возвращаемые параметры используются в операторе execute, который является частью пакета, то значения возвращаемых параметров вместе с заголовком выводятся на экран перед выполнением последующих операторов пакета.

    declare @tranName DObjectName
    declare @retCode integer
    begin
    
    	execute tran_Begin @tranName output
    
    select @tranName
    .........................................

    Oracle

    Создание процедур

    create or replace procedure my_proc(i in number := 123,
       j out number, k in out number /* error := 123 */)
    as
    begin
        dbms_output.put_line('i = ' || i);
        dbms_output.put_line('j = ' || j);
        dbms_output.put_line('k = ' || k);
    
        if i is null then
            return;
        end if;
    
    -- error
    --    i := 10;
        j := 20;
        k := 30;
    end;
    
    create or replace procedure my_proc_error
      (i number /* error (1) */, s varchar2 /* error (10) */)
    as
    begin
        null;
    end;
    
    declare
        a number;
        b number;
        c number;
    begin
        a := 1;
        b := 2;
        c := 3;
        my_proc(a, b, c);
    
        dbms_output.put_line('a = ' || a);
        dbms_output.put_line('b = ' || b);
        dbms_output.put_line('c = ' || c);
    end;

    Создание функций

    create or replace function my_fun(i in number) return number
    as
        j number;
    begin
        j := i+10;
        return j;    
    end;
        
    declare
        a number;
    begin
        a := 12+my_fun(10);
        dbms_output.put_line('a = ' || a);
    end;
    
    create or replace function my_fun(i in number) return number
    as
        j number;
    
        procedure p(n in out number)
        as
        begin
            n := n+i+j;        
        end;
    begin
        j := 3;
        p(j);
        j := j+i+10;
        return j;    
    end;
        
    declare
        a number;
    begin
        a := 12+my_fun(10);
        dbms_output.put_line('a = ' || a);
    end;

    Вызов процедур и функций

    create or replace procedure my_p
     (s varchar2, i number := 10, j number := 20)
    as
    begin
        null;
    end;
    
    declare
        a number;
        b number;
        s varchar2(100);
    begin
        my_p(s);
        my_p(s, a);
        my_p(s, a, b);
        my_p(s=>s, j=>b);
        my_p(s, j=>b);
    end;

    Передача параметров. Атрибут NOCOPY

    create or replace procedure my_p2
     (s1 out varchar2, s2 in out nocopy varchar2)
    as
    begin
        s1 := 'aaaaaaaaaaaaaaaaaaaaaaaaaa';
        s2 := 'bbbbbbbbbbbbbbbbbbbbbbbbbb';
    end;

    Модули PL/SQL

    create or replace package PackageTest
    as
        type point is record
            (
                x number,
                y number
             );
    
        tpoint point;
        n number;
             
        procedure p(ii in number, ss out varchar2);
        function f(n in point) return number;
        function f(x in number, y in number) return number;
    end PackageTest;
    
    create or replace package body PackageTest
    as
        type t1 is record
            (
                i number,
                j number
             );
    
        cnt number;
        trow1 test%rowtype;
         
        procedure p(ii in number, ss out varchar2)
        is
        begin
            select s into ss from test where i = ii;
        exception
            when no_data_found then
                ss := 'empty string';
        end;
    
        function f(n in point) return number
        as
        begin
            return n.x+n.y;
        end;
    
        function f(x in number, y in number) return number
        as
        begin
            return x+y;
        end;
    begin
        trow1.i := 1;
        trow1.s := 'null string';
        n := 100;
        cnt := -10;
    end PackageTest;
    
    create or replace procedure PackageTest_test
    as
    -- error
    --    d1 PackageTest.tl;
        s varchar2(100);
        n PackageTest.point;
    begin
        n.x := 100;
        n.y := 200;
        PackageTest.p(1, s);
        dbms_output.put_line('s = ' || s);
        dbms_output.put_line('f((100, 100)) = ' || PackageTest.f(n));
        dbms_output.put_line('f(100, 100) = ' || PackageTest.f(n));
        dbms_output.put_line('n = ' || PackageTest.n);
    -- error
    --    dbms_output.put_line('cnt = ' || PackageTest.cnt);
    end;

    Просмотр объектов и компиляция

    desc user_objects
    
    select object_name, object_type, status from user_objects;

    Перекомпиляция процедур и функций

    create or replace function f(i in number)
    return varchar2
    as
    begin
        return to_char(i+1);
    end;
    
    create or replace procedure p(ii in number, ss out varchar2)
    as
    begin
        select s into ss from test where i = ii;
    exception
        when no_data_found then
            ss := 'no data';
    end;
    
    select substr(object_name, 1, 30), object_type, 
      status from user_objects;
    
    select substr(object_name, 1, 30), object_type, 
         status from user_objects where object_type in 
                 ('PROCEDURE', 'FUNCTION', 'PACKAGE', 
                   'PACKAGE BODY') and (object_name like 'P%' 
                     or object_name like 'F%');
    
    declare
        i number;
        s varchar2(100);
    begin
        i := 10;
        s := f(i);
        dbms_output.put_line(s);
    
        i := 1;
        p(i, s);
        dbms_output.put_line(s);
    end;
    
    alter table test add h date;
    alter table test drop column h;
    
    alter procedure p compile;
    
    select * from user_errors;
    
    alter function f compile;
    
    alter package packagetest compile specification;
    alter package packagetest compile body;
    alter package packagetest compile package;
    
    select substr(object_name, 1, 30), object_type, 
         status from user_objects where object_type in 
                 ('PROCEDURE', 'FUNCTION', 'PACKAGE', 
                    'PACKAGE BODY') and (object_name like 'P%'
                       or object_name like 'F%');
    
    select * from user_errors;

    Скрипт для перекомпиляции процедур и функций

    Необходимо поместить в файл, запуск @<file>.sql

    ----------------------------------------------------
    set echo off
    set linesize 1000
    set pagesize 500
    set heading off
    set feedback off
    spool c:\tmp\a.sql
    select 'ALTER ' || object_type || ' ' || object_name || ' COMPILE;
      ' from user_objects where object_type in 
            ('PROCEDURE', 'FUNCTION', 'PACKAGE');
    select 'SELECT * FROM USER_ERRORS;' from dual;
    spool off
    @c:\tmp\a.sql
    host del c:\tmp\a.sql
    -----------------------------------------------------

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

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

    Презентация по 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 СУБД

    Презентация

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