DBMS_SQL 執行查詢示例

一般狀況下,須要動態執行查詢語句儘可能使用語法更簡潔的 OPEN {SYS_REFCURSOR} FOR ... 或 EXECUTE IMMEDIATE ...編程

當查詢語句的列或綁定變量沒法肯定數量或類型時,仍是須要使用更加靈活的 DBMS_SQL 包,下面是使用 DBMS_SQL 包執行列數量可變的查詢示例;一個典型的應用場景就是報表的生成,由於咱們可能沒法事先知道這個報表有多少列。函數

DECLARE
  -- 可變列數的報表查詢編程示例
  l_Cursor_Id INTEGER;
  l_Col_Count INTEGER;
  l_Desc_Tbl2 Dbms_Sql.Desc_Tab2;
  l_Ret       INTEGER;
  l_Row_Count BINARY_INTEGER := 0;
  l_Row_Index BINARY_INTEGER := 1;
  c_Bulk_Size CONSTANT BINARY_INTEGER := 2; -- 每次提取的記錄數
  -- 報表的每一列最終都是 VARCHAR2 類型
  TYPE Col_Val_Tbl_Type IS TABLE OF Dbms_Sql.Varchar2_Table INDEX BY PLS_INTEGER;
  l_Col_Val_Tbl Col_Val_Tbl_Type;
BEGIN
  -- 打開並解析查詢語句
  l_Cursor_Id := Dbms_Sql.Open_Cursor;
  Dbms_Sql.Parse(l_Cursor_Id,
                 'SELECT ''X'' M, ''Y'' M FROM DUAL WHERE DUMMY = :T_DUMMY
UNION ALL SELECT ''C'', ''D'' FROM DUAL
UNION ALL SELECT ''E'', ''F'' FROM DUAL',
                 Dbms_Sql.Native);
  -- 根據查詢語句的列取出全部值
  Dbms_Sql.Describe_Columns2(l_Cursor_Id, l_Col_Count, l_Desc_Tbl2);
  FOR i IN 1 .. l_Col_Count LOOP
    l_Col_Val_Tbl(i)(0) := NULL;
    Dbms_Sql.Define_Array(c           => l_Cursor_Id,
                          Position    => i,
                          c_Tab       => l_Col_Val_Tbl(i),
                          Cnt         => c_Bulk_Size,
                          Lower_Bound => l_Row_Index);
  END LOOP;
  -- 綁定變量並執行
  Dbms_Sql.Bind_Variable(l_Cursor_Id, ':T_DUMMY', 'X');
  l_Ret := Dbms_Sql.Execute(l_Cursor_Id); -- 返回 DML 語句的修改行數,此處不使用
  -- 遍歷查詢結果
  LOOP
    l_Row_Count := l_Row_Count + Dbms_Sql.Fetch_Rows(l_Cursor_Id);
    EXIT WHEN l_Row_Count < l_Row_Index; -- 取出記錄後總行數未增長
    -- Dbms_Output.Put_Line('FETCH: ' || (l_Row_Count - l_Row_Index + 1));
    -- 取每一列的值
    FOR j IN 1 .. l_Col_Count LOOP
      Dbms_Sql.Column_Value(l_Cursor_Id, j, l_Col_Val_Tbl(j));
    END LOOP;
    -- 遍歷每一行
    FOR i IN l_Row_Index .. l_Row_Count LOOP
      FOR j IN 1 .. l_Col_Count LOOP
        -- 遍歷每一列
        Dbms_Output.Put(l_Col_Val_Tbl(j) (i) || ' ');
      END LOOP;
      Dbms_Output.Put_Line('');
    END LOOP;
    EXIT WHEN l_Row_Count - l_Row_Index + 1 < c_Bulk_Size; -- 本次取出的行數小於指定的值,不進行下次取值
    l_Row_Index := l_Row_Count + 1;
  END LOOP;
  -- 關閉
  IF Dbms_Sql.Is_Open(l_Cursor_Id) THEN
    Dbms_Sql.Close_Cursor(l_Cursor_Id);
  END IF;
END;spa

DBMS_SQL 包還提供了兩個很棒的函數用於在 DBMS_SQL 的 CURSOR_NUMBER 和 SYS_REFCURSOR 之間切換,咱們能夠充分利用兩者的長處:CURSOR_NUMBER 更靈活,SYS_REFCURSOR 更簡潔。it

例如上述示例在綁定變量上沒有不肯定性,只須要動態變化查詢到的列,那麼能夠先使用語法簡潔的 SYS_REFCURSOR 打開查詢,而後切到 CURSOR_NUMBER 對列進行分析。io

這兩個函數的定義及說明以下:function

function to_refcursor(cursor_number in out integer) return sys_refcursor;class

CURSOR_NUMBER 必須是一個已經執行過(調用過 DBMS_SQL.EXECUTE)的查詢,調用後遊標的控制權轉移到返回的 SYS_REFCURSOR 變量上,後續應且僅應 CLOSE SYS_REFCURSOR;變量

function to_cursor_number(rc in out sys_refcursor) return integer;遍歷

SYS_REFCURSOR 必須是一個已經打開(執行過 OPEN ... FOR ..)的查詢,調用後遊標的控制權轉移到返回的 CURSOR_NUMBER 變量上,後續應且僅應 DBMS_SQL.CLOSE_CURSOR(CURSOR_NUMBER);語法

相關文章
相關標籤/搜索