КаталогИндекс раздела
НазадОглавлениеВперед


7.3 Хранимые процедуры

7.3.1 Очевидно, что, как и в любых других приложениях, в приложениях баз данных часто возникает необходимость выполнения одних и тех же или сходных подзадач, включающих в себя одинаковое манипулирование данными, хранимыми в базе данных. Как и в процедурных языках, в языке SQL возникла концепция процедур - отдельно описанных, повторно используемых последовательностей операций, выполняющих, как правило, определенную прикладную функцию. В современных приложения баз данных эта концепция развилась в концепцию хранимых процедур. Хранимая процедура представляет собой процедуру, находящуюся и выполняющуюся на сервере базы данных и содержащую операторы SQL и операторы процедурной логики (операторы процедурного SQL или другого языка программирования). В современных информационных технологиях перенос как можно большей части бизнес-логики в хранимые процедуры базы данных является стратегической концепцией. Хранимые процедуры обеспечивают приложениям баз данных следующие преимущества:

Как уже упоминалось, процедурная логика в хранимых процедурах может быть реализована на любом языке, допускающем включение в программу обращения к базе данных. В Oracle традиционно основным языком хранимых процедур является язык PL/SQL, но поддерживаются и процедуры на других языках, прежде всего - на языке C, а в последнее время - также на языке Java. В DB2 в отсутствие процедурного расширения SQL существовал богатый набор языков, применяющихся для написания хранимых процедур: C, REXX, COBOL и т.д. С развитием языка Java он становится в IBM стратегическим средством для написания хранимых процедур, которое поддерживается специальными средствами (например, Java Stored Procedure Builder). В DB2 версии 7.1 в хранимых процедурах становится возможным применение процедурного SQL, что составляет второе стратегическое направление.

К сожалению, объем и направленность нашего учебного пособия на дает нам возможности в полной мере рассмотреть свойства хранимых процедур и методы их создания. Поскольку в большой степени хранимые процедуры предназначены для реализации бизнес-логики, их рассмотрение должно относится к курсу или разделу "Проектирование приложений баз данных". Мы ограничимся рассмотрением основных свойств и одним примером.

7.3.2 Хранимая процедура создается оператором SQL CREATE PROCEDURE, общий синтаксис которого представлен на рис. 7.3.


Рисунок 7.3 - Синтаксис оператора CREATE PROCEDURE

Этот оператор во многом похож на определения процедур в процедурных языках программирования (Pascal, C, etc.). Принципиальное отличие процедуры SQL состоит в том, что для процедуры обязательно должен быть описан режим использования каждого параметра: IN (только входной), OUT (только выходной), INOUT (и входной, и выходной). В Oracle режим использования указывается после имени параметра, в DB2 - перед именем параметра.

Результат хранимой процедуры может передаваться через выходные параметры или представлять собой множество строк, выбранное из базы данных. В последнем случае в процедуре открывается курсор (возможно, несколько курсоров) и вызвавшее процедуру приложение выбирает данные из этого курсора. В DB2 для этого случая в операторе CREATE PROCEDURE применяются дополнительные конструкции.

Специально обращаем ваше внимание на то, что тело процедуры в DB2 представляет собой оператор SQL (в частности, это может быть составной оператор BEGIN ... END), а в Oracle тело процедуры строится по правилам PL/SQL.

Здесь рассмотрен только случай для хранимых процедур, написанных на языке SQL (PL/SQL), но обе СУБД предусматривают также и использование для этих целей других языков. В последнем случае процедуры являются "внешними" (описаны отдельно) и синтаксис оператора CREATE PROCEDURE несколько отличается для этого случая.

Хранимая процедура вызывается из приложения оператором SQL CALL (стандарт и DB2):

    CALL имя_процедуры (список_фактических_параметров)

В PL/SQL Oracle вызов процедуры состоит просто в употреблении ее имени со списком параметров:

    имя_процедуры (список_фактических_параметров)

Обе СУБД обеспечивают также процедуры-функции (оператор CREATE FUNCTION).

7.3.3 В качестве примера хранимой процедуры рассмотрим те задачи, с которыми мы "не справились", создавая триггеры для Oracle:

Мы создадим одну процедуру с именем upd_salary, которая будет обеспечивать указанные ограничения при изменении зарплаты любого сотрудника. Эта процедура должна выполняться при изменении зарплаты любого сотрудника вместо оператора UPDATE. Параметры процедуры:

    CREATE PROCEDURE upd_salary 
       (id IN NUMBER, salary IN NUMBER, type IN CHAR)
      IS 
       old_salary NUMBER; /* старая зарплата */
       p_salary NUMBER;   /* зарплата президента */
       new_salary NUMBER; /* новая зарплата */
       x_job NUMBER; /* код должности сотрудника */
        BEGIN
          /* выбирается старая зарплата и код должности
           сотрудника, зарплата которого изменяется */
          SELECT salary,job_id INTO old_salary,x_job FROM employee WHERE employee_id=id; 
          /* вычисляется новая зарплата */
          IF type='S' THEN new_salary:=salary;
          ELSIF type='A' THEN new_salary:=old_salary+salary;
          ELSE raise_application_error(-20777,'Param error');
          END IF;
          /* является ли сотрудник президентом? */
          IF x_job=672 THEN
            /* уменьшается ли зарплата президента ? */
            IF (old_salary>new_salary)THEN
              /* да - изменяется зарплата у всех */
              UPDATE employee SET salary=salary*new_salary/old_salary;
            ELSE
              /* нет - только зарплата президента */
              UPDATE employee SET salary=new_salary WHERE employee_id=id;
            END IF;
          ELSE
            /* если сотрудник - не президент, выбирается зарплата президента */
            SELECT salary INTO p_salary FROM employee WHERE job_id=672; 
            /* зарплата больше президентской ? */
            IF p_salary<new_salary THEN
              /* да - ошибка */
              raise_application_error(-20777,'Salary limit');
            ELSE        
              /* нет - изменение выполняется */
              UPDATE employee SET salary=new_salary WHERE employee_id=id;
            END IF;
          END IF;
        END;   
    /

Хотя мы и справились с этими задачами в триггерах DB2, реализуем то же самое в виде хранимой процедуры DB2.

    CREATE PROCEDURE UPD_SALARY (IN id DECIMAL(8,2), IN salary DECIMAL(8,2), IN type CHAR(1))
      LANGUAGE SQL
       BEGIN
         -- старая зарплата
         DECLARE old_salary DECIMAL(8,2); 
         -- зарплата президента
         DECLARE p_salary DECIMAL(8,2); 
         -- новая зарплата
         DECLARE new_salary DECIMAL(8,2);
         -- код должности сотрудника 
         DECLARE x_job INTEGER;
         -- выбирается старая зарплата и код должности сотрудника, зарплата которого изменяется 
         SET old_salary= (SELECT salary FROM employee WHERE employee_id=id); 
         SET x_job= (SELECT job_id FROM employee WHERE employee_id=id); 
         -- вычисляется новая зарплата 
         IF type='S' THEN SET new_salary=salary;
         ELSEIF type='A' THEN SET new_salary=old_salary+salary;
         ELSE SIGNAL SQLSTATE '75001' ('Parameter error');
         END IF;
         -- является ли сотрудник президентом? 
         IF x_job=672 THEN
           -- уменьшается ли зарплата президента ? 
           IF (old_salary>new_salary) THEN
             -- да - изменяется зарплата у всех 
             UPDATE employee SET salary=salary*new_salary/old_salary;
           ELSE
             -- нет - только зарплата президента 
             UPDATE employee SET salary=new_salary WHERE employee_id=id;
           END IF;
         ELSE
           -- если сотрудник - не президент, выбирается зарплата президента 
           SELECT salary INTO p_salary FROM employee WHERE job_id=672; 
           -- зарплата больше президентской ? 
           IF p_salary<new_salary THEN 
             -- да - ошибка 
             SIGNAL SQLSTATE '75001' ('Salary limitation');
           ELSE        
             -- нет - изменение выполняется 
             UPDATE employee SET salary=new_salary WHERE employee_id=id;
            END IF;
          END IF;
        END
    @

НазадОглавлениеВперед
КаталогИндекс раздела