Oracle12c中PL/SQL(DBMS_SQL)新特性之隱式語句結果

sqysl發表於2016-06-25
隱式資料結果特性將能簡化從其他資料庫到Oracle12c儲存過程遷移。
1. 背景
T-SQL中允許查詢結果的隱式返回。例如:下面T-SQL儲存過程隱式返回查詢結果。
CREATE PROCEDURE Get_Results
( @p_id  int )
AS
SELECT dscpt, crt_date FROM t1 WHERE id = @p_id
RETURN 0
GO
透過DBMS_SQL包中的RETURN_RESULT過程,Oracle 12c目前支援類似的功能。這在實施遷移時非常有用。
2. RETURN_RESULT
不是顯式定義參照遊標(ref cursor)輸出引數,DBMS_SQL包中的RETURN_RESULT過程允許結果隱式傳出,看下例。
CREATE table t1 (
  id           NUMBER,
  dscpt  VARCHAR2(30),
  crt_date DATE
);




INSERT INTO t1 VALUES (1, 'The value 1', SYSDATE-2);
INSERT INTO t1 VALUES (2, 'The value 2', SYSDATE-1);
INSERT INTO t1 VALUES (3, 'The value 3', SYSDATE);
COMMIT;
現在我們建立一個過程來返回一個或多個結果集。
CREATE OR REPLACE PROCEDURE get_results (p_id IN NUMBER DEFAULT NULL)
AS
  l_cursor_1 SYS_REFCURSOR;
  l_cursor_2 SYS_REFCURSOR;
BEGIN
  IF p_id IS NOT NULL THEN
    OPEN l_cursor_1 FOR
      SELECT dscpt, crt_date
      FROM   t1
      WHERE  id = p_id;




    DBMS_SQL.RETURN_RESULT(l_cursor_1);
  END IF;




  OPEN l_cursor_2 FOR
    SELECT COUNT(*)
    FROM   t1;




  DBMS_SQL.RETURN_RESULT(l_cursor_2);
END;
/
我們從sql*plus中執行該過程時,將會自動顯式顯示語句結果。
SQL> EXEC get_results(1);




PL/SQL procedure successfully completed.




ResultSet #1




DESCRIPTION                    CREATED_DATE
------------------------------ --------------------
The value 1                    06-JUL-2013 21:19:45




1 row selected.




ResultSet #2




  COUNT(*)
----------
         3




1 row selected.




SQL> EXEC get_my_results;




PL/SQL procedure successfully completed.




ResultSet #1




  COUNT(*)
----------
         3




1 row selected.




SQL>
透過RETURN_RESULT過程返回DBMS_SQL的遊標時也會存在一些限制和不足。
3. GET_NEXT_RESULT
一般來說,我們希望透過客戶端應用來處理這些結果集,這可以透過DBMS_SQL包的 GET_NEXT_RESULT過程來解決。
下例透過DBMS_SQL包來執行該過程。由於過程返回不同記錄結構的結果集,我們必須描述這些結果集以便進行處理。這可以透過結果集的列數來進行判斷。
SET SERVEROUTPUT ON
DECLARE
  l_sql_cursor    PLS_INTEGER;
  l_ref_cursor    SYS_REFCURSOR;
  l_return        PLS_INTEGER;




  l_col_cnt       PLS_INTEGER;
  l_desc_tab      DBMS_SQL.desc_tab;




  l_count         NUMBER;
  l_dscpt   t1.dscpt%TYPE;
  l_crt_date  t1.crt_date%TYPE;
BEGIN
  -- 執行過程
  l_sql_cursor := DBMS_SQL.open_cursor(treat_as_client_for_results => TRUE);




  DBMS_SQL.parse(c             => l_sql_cursor,
                 statement     => 'BEGIN get_results(1); END;',
                 language_flag => DBMS_SQL.native);




  l_return := DBMS_SQL.execute(l_sql_cursor);




  -- 迴圈遍歷每個結果集
  LOOP
    -- 獲取下個結果集
    BEGIN
      DBMS_SQL.get_next_result(l_sql_cursor, l_ref_cursor);
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        EXIT;
    END;




    -- 檢查結果集列數
    l_return := DBMS_SQL.to_cursor_number(l_ref_cursor);
    DBMS_SQL.describe_columns (l_return, l_col_cnt, l_desc_tab);
    l_ref_cursor := DBMS_SQL.to_refcursor(l_return);




    -- 根據列數處理結果集
    CASE l_col_cnt
      WHEN 1 THEN
        DBMS_OUTPUT.put_line('The column is COUNT:');
        FETCH l_ref_cursor
        INTO  l_count;




        DBMS_OUTPUT.put_line('l_count=' || l_count);
        CLOSE l_ref_cursor;
      WHEN 2 THEN
        DBMS_OUTPUT.put_line('The columns are DSCPT and CRT_DATE:');
        LOOP
          FETCH l_ref_cursor
          INTO  l_dscpt, l_crt_date;




          EXIT WHEN l_ref_cursor%NOTFOUND;




          DBMS_OUTPUT.put_line('l_dscpt=' || l_dscpt || '  ' ||
                               'l_crt_date=' || TO_CHAR(l_crt_date, 'DD-MON-YYYY'));
        END LOOP;
        CLOSE l_ref_cursor;
      ELSE
        DBMS_OUTPUT.put_Line('I wasn''t expecting that!');
    END CASE;
  END LOOP;
END;
/
The columns are DSCPT and CRT_DATE:
l_dscpt=The value 1  l_crt_date=06-JUL-2013
The column is COUNT:
l_count=3




PL/SQL procedure successfully completed.




SQL>
透過過程GET_NEXT_RESULT返回DBMS_SQL中的遊標時也會有一些限制和不足。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8484829/viewspace-2120969/,如需轉載,請註明出處,否則將追究法律責任。

相關文章