簡單學習--DB2存儲過程

    DB2 SQL Procedural Language(SQL PL)是SQL Persistent Stored Module 語言標準的一個子集。該標準結合了SQL 訪問數據的方便性和編程語言的流控制。經過SQL PL 當前的語句集合和語言特性,能夠用SQL 開發綜合的、高級的程序,例如函數、存儲過程和觸發器。這樣即可以將業務邏輯封裝到易於維護的數據庫對象中,從而提升數據庫應用程序的性能。
    SQL PL 支持本地和全局變量,包括聲明和賦值,還支持條件語句和迭代語句、控制語句的轉移、錯誤管理語句以及返回結果集的方法。這些話題將在本教程中討論。
變量聲明
    SQL 過程容許使用本地變量賦予和獲取SQL 值,以支持全部SQL 邏輯。在SQL 過程當中,在代碼中使用本地變量以前要先進行聲明。
DB2 數據類型

DEFAULT 值 —— 若是沒有指定,在聲明時將賦值爲NULL。
下面是變量聲明的一些例子:
sql

  • DECLARE v_salary DEC(9,2) DEFAULT 0.0;
  • DECLARE v_status char(3) DEFAULT 'YES';
  • DECLARE v_descrition VARCHAR(80);
  • DECLARE v1,v2 INTEGER DEFAULT 0;
請注意:從 DB2 version 9.5 開始才支持在一個DECLARE 語句中聲明多個相同數據類型的變量。

數組數據類型
    SQL 過程從9.5 版開始支持數組類型的變量和參數。要定義一個數組類型的變量,須要先在數據庫中建立該類型,而後在過程或應用程序中聲明它。數組是臨時的值,能夠在存儲過程和應用程序中操縱它,可是不能將它存儲到表中。
    數組類型的名稱應該用模式加以限定,而且在當前服務器上應該是唯一的。LONG VARCHAR、LONG VARGRPAHIC、XML 和用戶定義類型不能做爲數組元素的數據類型。
    下面是數組類型的例子: 數據庫

  • CREATE TYPE number as INTEGER ARRAY[100];
  • CREATE TYPE names as VARCHAR(30) ARRAY[];
  • CREATE TYPE MYSCHEMA totalcomp as DECIMAL(12,2) ARRAY[];

    請注意,整數「constant」 指定數組的最大基數,它是可選的。數組元素能夠經過ARRAY-VARIABLE(subindex) 來引用,其中subindex 必須介於1 到數組的基數之間。
    如今能夠在 SQL 過程當中使用這個數據類型:
在過程當中使用數組數據類型 express

  1. CREATE PROCEDURE PROC_VARRAY_test(out mynames names)
  2. BEGIN
  3. DECLARE v_pnumb numbers;
  4. SET v_pnumb = ARRAY[1,2,3,5,7,11];
  5. SET mynames(1) = 'MARINA';
  6.    
  7. ....
  8. END
    DB2 支持一些操做數組的方法。例如,函數CARDINALITY(myarray) 返回一個數組中元素的個數。
賦值
    SQL PL 提供了SET 語句來爲變量和數組元素賦值。
下面是一個 SET 語句的簡化的語法:
  •     SET variable_name = value/expression/NULL;
    這個變量名能夠是一個本地變量、全局變量或數組元素的名稱。
SET 語句的例子


  • SET var1  = 10;
  • SET total = (select sum(c1) from T1);
  • SET var2 = POSSTR('MYTEST', 'TEST');
  • SET v_numb(10) = 20;  --assign value of 20 to the 10th element
  • SET v_numb = ARRAY[1,2,3,4];  --fill up array with values of the array v_numb
爲變量賦值的其餘方法有:
  • VALUES INTO 
  • SELECT (or FETCH) INTO
VALUE INTO 和SELECT INTO 的例子
  • VALUES 2 INTO v1;
  • VALUES 'TEST' INTO var2;
  •     
  • SELECT SUM(c1) INTO var1 FROM T1;
  • SELECT POSSTR ('MYTEST', 'TEST') INTO v1 FROM SYSIBM.SYSDUMMY1;
專用寄存器
    專用寄存器(special register) 是 DBA 定義的一個存儲塊,供一個應用程序過程使用。寄存器中的值能夠在SQL 語句或SQL PL 語句中訪問和引用。在IBM DB2 database for Linux, UNIX, and Windows Information Center 能夠找到全部的專用寄存器。
    最經常使用的專用寄存器有:



  • CURRENT DATE
  • CURRENT TIME
  • CURRENT TIMESTAMP
  • CURRENT USER
  • CURRENT PATH
    全部這些寄存器均可以經過在名稱中加下劃線來引用。例如,CURRENT_DATE。


返回當前日期和時間的過程的例子


  1. CREATE PROCEDURE get_datetime(out cdate date, out ctime time)
  2. P1:BEGIN
  3.     VALUES CURRENT DATE INTO cdate;
  4.     VALUES CURRENT TIME INTO ctime;
  5. END P1
執行後,該過程返回
  • Name      Output
  • cdate     2012-10-26
  • ctime     15:40:23
    有些專用寄存器的值能夠經過SET 語句來更新。例如,爲了更新正在訪問的模式,須要像下面這樣更改專用寄存器CURRENT SCHEMA。



  • SET CURRENT_SCHEMA = MYSCHEMA
若要更改默認函數路徑,則須要更新專用寄存器CURRENT PATH。


遊標
聲明

    SQL PL 提供DECLARE cursor 語句來定義一個遊標,並提供其餘語句來支持返回其餘結果集和遊標處理。
遊標聲明的語法
>>-DECLARE--cursor-name--CURSOR---------->
>--FOR--+-select-statement-+-------------><
.-WITHOUT HOLD-.--+--------------+---------------------------------------------|
'-WITH HOLD----'
.-WITHOUT RETURN-------------.
|--+----------------------------+-------------------------------|
| .-TO CALLER-. |'-WITH RETURN--+-----------+-'-TO CLIENT-'
    Select-statement 是一條有效的 SQL SELECT 語句。能夠指定FOR UPDATE 子句,以便將遊標用於定位更新或刪除。
WITHOUT HOLD/WITH HOLD 選項定義 COMMIT 操做以後的遊標狀態(open/close)。默認狀況下爲WITHOUT HOLD。若是使用了WITH HOLD 選項定義一個遊標,那麼在COMMIT 操做以後,該遊標保持OPEN 狀態。在ROLLBACK 操做以後,全部遊標都將被關閉。
下面是一個顯式聲明遊標的例子,它能夠用於過程當中後面的迭代處理:
編程


  1. DECLARE mycur1 CURSOR
  2.     FOR SELECT e.empno, e.lastname, e.job
  3.         FROM employee e, department d
  4.         WHERE e.workdept = d.deptno
  5.             AND deptname = 'PLANNING';

雖然 SQL 語句不能包含參數佔位符,可是它能夠引用在遊標以前聲明的本地變量。例如:
使用本地變量的遊標聲明
數組

  1. DECLARE  v_dept CHAR(3) DEFAULT ' ';
  2. DECLARE myres_set CURSOR
  3.     FOR SELECT emp, lastname, job, salary, comm
  4.         FROM employee
  5.         WHERE workdept = v_dept;
遊標和結果集
    在 SQL 過程當中,除了迭代結果集中的行之外,遊標還能夠作更多的事情。遊標還可用於將結果集返回給調用程序或其餘過程。
  • WITHOUT RETURN/WITH return 選項指定遊標的結果表是否用於做爲從一個過程當中返回的結果集。
  • WITH RETURN TO CALLER 選項指定未來自遊標的結果集返回給調用者,後者能夠是另外一個過程或一個客戶機應用程序。這是默認選項。
  • WITH RETURN TO CLIENT 選項指定未來自遊標的結果集返回給客戶機應用程序,繞過任何中間的嵌套過程。
若要從一個過程當中返回結果集,須要:
  1. 建立一個過程,建立時指定DYNAMIC RESULT SETS 子句。
  2. 聲明遊標,聲明時指定WITH RETURN 子句。
  3. 打開該遊標,並使之保持open 狀態。
若是關閉該遊標,則結果集將不能返回給調用者應用程序。
返回一個結果集的遊標的聲明
  1. CREATE PROCEDURE emp_from_dept()
  2.     DYNAMIC RESULT SETS 1
  3.     P1:BEGIN
  4.         DECLARE c_emp_dept CURSOR WITH RETURN
  5.             FOR SELECT empno, lastname, job, salary, comm
  6.                 FROM employee
  7.                 WHERE workdept = 'E21';
  8.         OPEN c_emp_dept;
  9.      END P1
遊標處理
    爲了在一個過程當中處理一個遊標的結果,須要作如下事情:
  1. 在存儲過程塊的開頭部分DECLARE 遊標。
  2. 打開該遊標。
  3. 將遊標的結果取出到以前已聲明的本地變量中(隱式遊標處理除外,在下面的FOR 語句中將對此加以解釋)。
  4. 關閉該遊標。(注意:若是如今不關閉遊標,當過程終止時將隱式地關閉遊標)。
條件語句
    SQL PL 中支持兩種類型的條件語句— IF 語句和CASE 語句。
IF 語句
    經過 IF 語句能夠根據一個條件的狀態來實現邏輯的分支。IF 語句支持使用可選的ELSEIF 子句和默認的 ELSE 子句。END IF 子句是必需的,它用於代表 IF 語句的結束。
IF 語句示例
  1. IF years_of_serv > 30 THEN
  2.     SET gl_sal_increase = 15000;
  3. ELSEIF years_of_serv > 20 THEN
  4.     SET gl_sal_increase = 12000;
  5. ELSE
  6.     SET gl_sal_increase = 10000;
  7. END IF;

CASE 語句
    SQL PL 支持兩種類型的CASE 語句,以根據一個條件的狀態實現邏輯的分支: 服務器

  • simple CASE 語句用於根據一個字面值進入某個邏輯。
  • searched CASE 語句用於根據一個表達式的值進入某個邏輯。
使用searched CASE 語句的存儲過程
  1. CREATE PROCEDURE sal_increase_lim1(empid CHAR(6))
  2. BEGIN
  3.     DECLARE years_of_serv INT DEFAULT 0;
  4.     DECLARE v_incr_rate DEC(9,2) DEFAULT 0.0;
  5.     SELECT YEAR(CURRENT DATE) - YEAR(hiredate)
  6.         INTO years_of_serv
  7.         FROM empl1
  8.         WHERE empno = empid;
  9.     
  10.     CASE
  11.         WHEN years_of_serv > 30 THEN 
  12.             SET v_incr_rate = 0.08;
  13.         WHEN years_of_serv > 20 THEN
  14.             SET v_incr_rate = 0.07;
  15.         WHEN years_of_serv > 10 THEN
  16.             SET v_incr_rate = 0.05;
  17.         ELSE
  18.             SET v_incr_rate = 0.04;
  19.     END CASE;
  20.     
  21.     UPDATE empl1
  22.         SET salary = salary + salary * v_incr_rate;
  23.     WHERE empno = empid;

  24. END
迭代語句
    SQL PL 支持一些重複執行某個邏輯的方法,包括簡單的LOOP、WHILE 循環、REPEAT 循環和FOR 循環:
  • LOOP 循環-- 簡單的循環


    • L1: LOOP
    •     SQL statements;
    •     LEAVE L1;
    • END LOOP L1;
  • WHILE 循環-- 進入前檢查條件
    • WHILE condition
    • DO
    •     SQL statements
    • END WHILE;
  • REPEAT 循環-- 退出前檢查條件
    • REPEAT
    •     SQL statements;
    •     UNTIL condition
    • END REPEAT;
  • FOR 循環-- 結果集上的隱式循環
    • FOR loop_name AS
    •     SELECT … FROM
    • DO
    •     SQL statements;
    • END FOR;
    請注意,FOR 語句不一樣於其餘的迭代語句,由於它用於迭代一個定義好的結果集中的行。

    爲了演示這些循環技巧的使用,咱們來編寫一個過程,該過程從一個EMPLOYEE 表中獲取每一個僱員的姓氏、工做年限和年齡,並將其插入到新表REPORT_INFO_DEPT 中,這些信息分別被聲明爲lname varchar(15)、hiredate date 和birthdate date。
    請注意,使用一個簡單的SQL 語句也能夠作一樣的事情,可是在這個例子中咱們使用3 種不一樣的循環語句。
簡單的循環例子 編程語言

  1. CREATE PROCEDURE LEAVE_LOOP(DEPTIN char(3), OUT p_counter INTEGER)
  2. L1:BEGIN
  3.     DECLARE v_at_end, v_counter INTEGER DEFAULT 0;
  4.     DECLARE v_lastname VARCHAR(15);
  5.     DECLARE v_birthd, v_hired DATE;
  6.     
  7.     DECLARE c1 CURSOR
  8.         FOR SELECT lastname, hiredate, birthdate FROM employee
  9.             WHERE WORKDEPT = deptin;
  10.     
  11.     DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_at_end = 1;
  12.                         --聲明循環中止的條件
  13.     OPEN c1;
  14.     FETCH_LOOP: LOOP
  15.     FETCH c1 INTO v_lastname, v_hired, v_birthd;  
  16.         IF v_at_end <> 0 THEN   --loop until last row of the cursor
  17.             LEAVE FETCH_LOOP;
  18.         END IF;
  19.         SET v_counter = v_counter + 1;
  20.         INSERT INTO REPORT_INFO_DEPT
  21.             values(v_lastname, v_hired, v_birthd);
  22.     END LOOP FETCH_LOOP;
  23.     SET p_counter = v_counter;
  24. END L1;

WHILE 循環的例子 函數

  1. CREATE PROCEDURE DEPT_REPT(DEPTIN char(3), OUT p_counter INTEGER)
  2. P1:BEGIN
  3.     DECLARE v_at_end, v_counter INTEGER DEFAULT 0;
  4.     DECLARE v_lastname, VARCHAR(15);
  5.     DECLARE v_birthd, v_hired DATE;
  6.     
  7.     DECLARE c1 CURSOR
  8.         FOR SELECT lastname, hiredate, birthdate FROM employee
  9.             WHERE WORKDEPT = deptin;
  10.     
  11.     DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_at_end = 1;
  12.     
  13.     OPEN c1;
  14.     FETCH c1 INTO v_lastname, v_hired, v_birthd;
  15.     WHILE(v_at_end = 0)
  16.     DO
  17.         INSERT INTO REPORT_INFO_DEPT
  18.             values(v_lastname, v_hired, v_birthd);
  19.         SET v_counter = v_counter + 1;
  20.         FETCH c1 INTO v_lastname, v_hired, v_birthd;
  21.     END WHILE;
  22.     SET p_counter = v_counter;
  23. END P1
    REPEAT 循環很是相似於WHILE 循環,只不過條件是在最後檢查的(所以,它其實是一個UNTIL 循環)。
 FOR 循環的例子   
  1. CREATE PROCEDURE DEPT_REPT1(DEPT char(3), OUT p_coumter INTEGER)
  2. P1:BEGIN
  3.     DECLARE v_counter INT DEFAULT 0;
  4.     FOR dept_loop AS
  5.         SELECT lastname, hiredate, birthdate FROM employee
  6.             WHERE WORKDEPT = deptin ----注意,這裏是沒有分號的
  7.     DO
  8.         INSERT INTO DEPORT_INFO_DEPT values
  9. (dept_loop.lastname, dept_loop.hiredate, dept_loop.birthdate);
  10.         SET v_counter = v_counter + 1;
  11.     END FOR;
  12.     SET p_coumter = v_counter;
  13. END P1
    請注意,最後一個過程沒有打開遊標、從遊標中取數據或關閉遊標— 全部這些都是由 FOR 循環語句隱式進行的。並且,能夠引用循環中隱式地獲取的值,使用循環名稱限定列(例如dept_loop.lastname )— 而沒必要使用本地變量來存儲這些值。

異常處理機制
DECLARE 有名稱的條件
    SQL PL 容許爲給定的SQLSTATE 聲明用戶命名的條件,以用於以後的錯誤處理。條件名稱在整個複合語句中必須是唯一的,而且只能在明它的複合語句中引用它。
    聲明一個有名稱的條件的語法
oop

  • |--DECLARE--condition-name
    --CONDITION--FOR---------------------->
    .-VALUE-.
    .-SQLSTATE--+-------+-.
    >--+---------------------+--string-constant
    ---------------------|
下面是條件聲明的例子


  • DECLARE FOREIGN_KEY_VIOLATION CONDITION FOR SQLSTATE ‘23503’;
  • DECLARE overflow CONDITION FOR SQLSTATE '22003';
DECLARE 條件處理程序
    若是發生一個錯誤,存儲過程的行爲是根據條件處理程序來決定的。在一個存儲過程當中,能夠爲一個普通的或有名稱的條件和特定的SQLSTATE 聲明一個或多個條件處理程序。當一個SQL 語句產生一個SQLEXCEPTION 或SQLWARNING(SQLCODE <> 0)時,控制被轉移到爲一個聲明的處理程序中,以獲取普通的異常或特定的SQLSTATE 值。
處理程序聲明的語法
  • |--DECLARE--+-CONTINUE-+--HANDLER--FOR-------------------------->
    +-EXIT-----+
    '-UNDO-----'
    >--+-specific-condition-value
    -+--| SQL-procedure-statement |----|
    '-general-condition-value
    --'
    WHERE specific-condition-value
    .-,----------------------------------------.
    V .-VALUE-. |
    |----+-SQLSTATE--+-------+--string-constant
    -+-+-----------------|
    '-condition-name
    -----------------------'-+-+-----------------|
    '-condition-name
    -----------------------'
    下面是演示它如何工做的一些例子。在下面的過程當中,若是UPDATE 語句失敗,則控制被轉移到EXIT 處理程序。結果,該過程被終止,可是它的輸出參數包含SQLCODE 和SQLSTATE 的值。
  1. CREATE PROCEDURE simple_error
  2.     (IN new_job CHAR(8), IN p_empno CHAR(6),
  3.         OUT p_state_out CHAR(5),OUT p_code_out INT)
  4. SPECIFIC simple_error1
  5. BEGIN
  6.     DECLARE SQLCODE INT DEFAULT 0;
  7.     DECLARE SQLSTATE CHAR(5) DEFAULT ‘00000’;
  8.     DECLARE EXIT HANDLER FOR SQLEXCEPTION
  9.         SELECT SQLSTATE, SQLCODE
  10.             INTO p_sqlstate_out, p_sqlcode_out
  11.             FROM SYSIBM.SYSDUMMY1;
  12.     UPDATE EMPLOYEE
  13.         SET job = new_job
  14.         WHERE empno = p_empno;
  15. END
    請注意,SQLCODE 和SQLSTATE 應該被顯式地聲明爲本地變量。
具備CONTINUE 處理程序的過程
  1. CREATE PROCEDURE proc1 (IN num int, IN new_status varchar(10))
  2. P1: BEGIN
  3.     DECLARE SQLCODE INTEGER default 0;
  4.     DECLARE SQLSTATE CHAR(5) default ‘ ‘;
  5.     DECLARE v_trunc INTEGER default 0;
  6.     DECLARE overflow CONDITION FOR SQLSTATE '22001';
  7.     DECLARE CONTINUE HANDLER FOR overflow
  8.         BEGIN
  9.             INSERT INTO tab1 VALUES (num, substr (new_sataus,1,5));
  10.             SET v_trunc = 2;
  11.         END;
  12.     INSERT INTO tab1 VALUES(num,new_status);
  13.     RETURN v_trunc;
  14. END P1
    若是以 ‘Too many’ 做爲輸入參數new_status 的值調用這個過程,那麼在INSERT 語句執行期間會產生SQLSTATE ‘22001’,控制被轉移到CONDITION HANDLER。結果,v_trunc 指示符將被設置爲2,新行將被插入到TAB1 表中,插入時對COL2 列使用了截短後的值,該過程最終成功完成。
強制發出異常-- SIGNAL SQLSTATE
    SQL PL 支持發出一個錯誤或警告條件。這致使一個具備指定SQLSTATE 的錯誤或警告被返回,同時返回的還有可選的消息文本。
SIGNAL 語句的語法
  • >>-SIGNAL------------------------------------------------------->
    .-VALUE-.
    >--+-SQLSTATE--+-------+--+-sqlstate-string-constant
    -+-+-------->
    | '-variable-name
    ------------' |
    '-condition-name
    ------------------------------------'
    >--+------------------------+----------------------------------><
    '|--+-SET MESSAGE_TEXT-- = --diagnostic-string-expression
    -+------|
    能夠以包含 5 個字符的字符串常量的形式發出一個用戶定義的SQLSTATE。它必須以數字七、8 或9 或者字母I 到Z 開始。還能夠發出一個特定的條件名稱,可是必須在包含SIGNAL 語句的複合語句中聲明它,以下所示。
  • DECLARE condition overflow for SQLSTATE ‘22001’;
  • ….
  • SIGNAL overflow SET MESSAGE_TEXT = ‘Too many characters, truncated’;
SIGNAL 語句的使用


  1. CREATE PROCEDURE sign_test (IN num int, IN new_status varchar(10))
  2. P1: BEGIN
  3.     DECLARE SQLCODE INTEGER default 0;
  4.     DECLARE SQLSTATE CHAR(5) default '';
  5.     
  6.     IF length (new_status) > 5 THEN
  7.         SIGNAL SQLSTATE '72001' SET MESSAGE_TEXT = 'INPUT VALUE TOO LONG';
  8.     END IF;
  9.     INSERT INTO TAB1 VALUES (num, new_status);
  10. END P1
    在本教程中,您學習了用於編寫過程、用戶定義函數和觸發器的SQL Procedural Language。您學習了SQL Procedure Language 的全部基本要素,包括變量聲明和賦值、語法和使用以及用於控制過程邏輯的流程的條件語句和迭代語句。您還學習瞭如何使用錯誤處理和結果集。這使您可以構建可集成到數據庫應用程序中的定製的、複雜的業務邏輯。
相關文章
相關標籤/搜索