将PL / SQL sys_refcursor提取到记录表中

问题描述 投票:0回答:1

我试图从先前返回到记录表中的列中获取列。但是,当我在包体中运行代码时,我收到以下错误:

ORA-06504: PL/SQL: Return types of Result Set variables or query do not match

但是,当我尝试在PL / SQL匿名块窗口中执行此操作时,我可以使用批量收集指令成功获取记录。

以下是我的成功尝试:

DECLARE
--
O_ref SYS_REFCURSOR; 

-- Variable and types declaration.
TYPE REC_TYP is record  (
     column_1     number(8),
     column_2     varchar2(13)
  );

TYPE TAB_TYP is table of REC_TYP;

L_tab_typ   TAB_TYP;
--
BEGIN
  -- 
  open O_ref for 
    select sku,
           upc 
      from upc_ean
     where sku = 2004030; 
    --     
  LOOP
    --
      FETCH O_ref BULK COLLECT into L_tab_typ;
      EXIT WHEN L_tab_typ.COUNT = 0;
      --
      FOR indx IN 1 .. L_tab_typ.COUNT 
      LOOP
        --
        dbms_output.put_line('SKU: ' || L_tab_typ(indx).column_1);
        dbms_output.put_line('UPC: ' || L_tab_typ(indx).column_2);
        --
      END LOOP;
      --
  END LOOP;
  --
  CLOSE O_ref;
  --
END;

当我运行此代码时,我得到以下输出:

SKU: 2004030
UPC: 5601126003439
SKU: 2004030
UPC: 5601126039056

在包体中我有以下内容:

为什么这不适用于常规包装?

FUNCTION GET_STORE_ITEMS(I_store           IN   number
                         ----------- output ------------
                         O_item_data       OUT  NB_TAB_ITEM_DETAIL, -- i want to return a table type after I get the info from the sys_ref
                         ----------- error -------------
                         O_error_message   OUT  VARCHAR2)
  RETURN BOOLEAN IS
    --
    L_tab_type        NB_TAB_ITEM_DETAIL;
    L_sys_ref         SYS_REFCURSOR;
    L_test_sku        number(8);
    --
    CURSOR C_GET_ITEMS IS
      --
      SELECT a.sku
        FROM win_store a
       WHERE a.store = I_store;
    --
  BEGIN
    --
    -- Loop over the fashion skus.
    FOR R_items IN C_GET_ITEMS LOOP
      --
      BEGIN
        --
        IF GET_ITEM_DETAIL(I_store         => I_store,
                           I_sku           => R_items.sku,
                           O_item_data     => L_sys_ref, -- returns a sys_refcursor with the same structure as the type
                           O_error_message => L_error_message) = FALSE THEN
          --
          O_error_message := NB_MESSGE40_SQL.EMESSAGE(L_error_message);
          RETURN FALSE;
          --
        END IF;
        --
        LOOP
        --
          FETCH L_sys_ref BULK COLLECT into L_tab_type; -- It jumps to when others exception
          EXIT WHEN L_tab_type.COUNT = 0;
          --
          FOR indx IN 1 .. L_tab_type.COUNT 
          LOOP
            --
            L_test_sku := L_tab_type(indx).sku;
            --
          END LOOP;
          --
        END LOOP;
        --                      
        END;                                        
        --
    END LOOP;
    --
    RETURN TRUE;
    --
  EXCEPTION
    --
    WHEN OTHERS THEN
      --
      -- ...
      RETURN FALSE;
      --
END GET_STORE_ITEMS;

谢谢!

database oracle plsql
1个回答
0
投票

我碰巧解决了这个问题。在获取sys_refcursor之前,必须声明一个package-spec级别类型,就像在匿名块中完成一样。

首先,在数据库中创建记录和表类型:

CREATE OR REPLACE TYPE NB_REC_ITEM_DETAIL AS OBJECT
  (
     column_1     number(8),
     column_2     varchar2(13)
  );

CREATE OR REPLACE TYPE NB_TAB_ITEM_DETAIL AS TABLE OF NB_REC_ITEM_DETAIL; 

但是,这个结构对于PL / SQL引擎是未知的,因此有必要在包规范中创建这些数据结构,如下所示:

TYPE REC_TYP is record  (
  column_1     number(8),
  column_2     varchar2(13)
);

TYPE TAB_TYP is table of REC_TYP;

现在可以从sys_refcursor获取数据。

    FUNCTION GET_STORE_ITEMS(I_store           IN   NUMBER,
                         ----------- output ------------
                         O_item_data       OUT  NB_TAB_ITEM_DETAIL,
                         ----------- error -------------
                         O_error_message   OUT  VARCHAR2)
  RETURN BOOLEAN IS
    --
    L_error_message   VARCHAR2(255);
    L_item_data_rec   REC_TYP;
    L_item_detail_ref SYS_REFCURSOR;
    --
    CURSOR C_GET_STORE_ITEMS IS
      --
      SELECT a.sku
        FROM win_store a
       WHERE a.store = I_store;  
    --
  BEGIN
    --
    -- Instantiate output structure object.
    --
    O_item_data := NB_TAB_ITEM_DETAIL();
    --
    -- Loop over the items in the store range.
    --
    FOR R_items IN C_GET_STORE_ITEMS LOOP
      --
      BEGIN
        --
        IF NB_ITEM_INFO_SQL.GET_ITEM_DETAIL(I_store         => I_store,
                                            I_sku           => R_items.sku,
                                            I_ean           => NULL,
                                            O_item_data     => L_item_detail_ref,
                                            O_error_message => L_error_message) = FALSE THEN
          --
          O_error_message := NB_MESSGE40_SQL.EMESSAGE(L_error_message);
          RETURN FALSE;
          --
        END IF;
        --
        -- Fetch info from item_data sys_refcursor to record type.
        --
        FETCH L_item_detail_ref INTO L_item_data_rec;
        EXIT WHEN L_item_detail_ref%NOTFOUND;
        --
        CLOSE L_item_detail_ref; 
        --
        O_item_data.extend();
        O_item_data(O_item_data.last) := nb_rec_item_detail(column_1       => L_item_data_rec.column_1 ,
                                                            column_2       => L_item_data_rec.column_2);
        --
        END;                                              
        --
    END LOOP;
    --
    RETURN TRUE;
    --
  EXCEPTION
    --
    WHEN OTHERS THEN
      -- ...
      RETURN FALSE;
      --
    --
  END GET_STORE_ITEMS;
© www.soinside.com 2019 - 2024. All rights reserved.