2010年1月13日 星期三

Equivalent of Oracle's Ref Cursor in DB2


/*
以 DB2 的語法來實現像 Oracle Ref cursor的做法:
 宣告:  DECLARE cursorname CURSOR [WITH HOLD] WITH RETURN FOR CUR1;
 程式主體:PREPARE CUR1 FROM dynamic string;
 開啟:  cursor OPEN cursorname;

My scenario:
1. 建立一個測試 table, 存放日期,年,月,日
2. 運用Session global variable存放年份,做為dynamic string裡的年度條件
3. DB2 procedure 裡傳回單一resultset及cursor的語法
4. 測試結果
*/

/*  建立測試table及運用CTE與Recursive SQL新增日期資料  */

CREATE TABLE T3
(
  DT   INTEGER,
  YEAR_N INTEGER,
  MONTH_N INTEGER,
  DAY_N  INTEGER
) IN USERSPACE1;

INSERT INTO T3
WITH N(COL1)
AS
(SELECT DATE('2000-01-01') FROM SYSIBM.DUAL
UNION ALL
SELECT COL1 + 1 DAY FROM N
WHERE YEAR(COL1 + 1 DAY) <= 2010
)
SELECT INT(COL1),YEAR(COL1),MONTH(COL1),DAY(COL1) FROM N

/*  建立session global variable  */

CREATE VARIABLE ADMINISTRATROR.YEAR_SET INTEGER

-- 給定值為2009
SET ADMINISTRATROR.YEAR_SET = 2009


/*  附帶說明:只有相同 session 才看得到 session global variable 設定值  
   測試再另使用db2cmd去看這個year_set
*/


C:\>db2 connect to orion

  資料庫連線資訊

 資料庫伺服器     = DB2/NT 9.7.0
 SQL 授權 ID      = ADMINIST...
 本端資料庫別名    = ORION

C:\>db2 values administrator.year_set

1
-----------
     -

  已選取 1 個記錄。

/*  建立 procedure sp_test 傳回一個 result  */

CREATE PROCEDURE SP_TEST
RESULT SETS 1
LANGUAGE SQL
BEGIN
  DECLARE SQLCODE INTEGER DEFAULT 0;
  DECLARE retcode INTEGER DEFAULT 0;
  DECLARE szSql VARCHAR(128);

  DECLARE TIMECUR CURSOR WITH HOLD WITH RETURN FOR CUR1;

  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION,
                 SQLWARNING,
                 NOT FOUND
  SET retcode = SQLCODE;

  SET szSql = 'SELECT DT FROM T3 WHERE YEAR_N = YEAR_SET';

  PREPARE CUR1 FROM szSql;
  OPEN TIMECUR;
END

/*  測試(需傳回所有2009年的日期)  */

C:\>db2 call sp_test

 結果集 1
 --------------

 DT
 -----------
   20090101
   20090102
   20090103
   20090104
   20090105
   20090106
   20090107
   20090108
   20090109
   20090110
   20090111
   .
   .
   .