【问题标题】:Oracle PL/SQL 6504 with BULK COLLECT带有 BULK COLLECT 的 Oracle PL/SQL 6504
【发布时间】:2018-02-16 09:19:11
【问题描述】:

我有一个简单的查询:

SELECT MEASURE_ID, MEASURE_VALUE FROM MY_TABLE;

目前只返回几条记录(将来会有很多):

8   265.7
7   559.6

此类表上的 DESC 提供:

Name         Null     Type         
------------ -------- ------------ 
MEASURE_ID   NOT NULL NUMBER       
MEASURE_VALUE         NUMBER(10,1) 

然后我定义了正确的 PL/SQL 类型:

CREATE OR REPLACE TYPE HASHMAP_NUM_TYPE_OBJ AS OBJECT (
    THE_ID                 NUMBER,
    THE_VALUE              NUMBER(10,1) 
);
CREATE OR REPLACE TYPE HASHMAP_NUM_TYPE IS TABLE OF HASHMAP_NUM_TYPE_OBJ;

并尝试使用 BULK COLLECT 获取记录:

stats_by_measure HASHMAP_NUM_TYPE;
...
OPEN cursor_1 FOR
    SELECT MEASURE_ID, MEASURE_VALUE
    FROM MY_TABLE;
...
FETCH cursor_1 BULK COLLECT INTO stats_by_measure;
...
CLOSE cursor_1;

但是我遇到了 Oracle -6504 错误。我做错了什么?

备注:如果我逐行获取相同的游标,使用这样的代码块:

foo                    NUMBER;
faa                    NUMBER(10,1);
my_obj                 HASHMAP_NUM_TYPE_OBJ;
...
LOOP
  FETCH cursor_1 INTO foo, faa;
  my_obj := HASHMAP_NUM_TYPE_OBJ(foo,faa);
  EXIT WHEN cursor_1%NOTFOUND;
END LOOP;

一切正常!

【问题讨论】:

  • 你为什么首先将行提取到数组中?你会怎么处理他们?我也想知道你为什么使用 ref 游标而不是显式(即“正常”)游标甚至隐式游标?
  • 你说得对,当然没必要。这只是我们应用的一种架构模式(在这种情况下没有任何理由),以便能够从“纯 PL/SQL 范式”切换到“Hibernate fetch cursor”范式(如果需要)。

标签: oracle plsql cursor bulk-collect


【解决方案1】:

修改你的光标查询,如下所示,使其具有相同的类型

OPEN cursor_1 FOR
    SELECT HASHMAP_NUM_TYPE_OBJ(MEASURE_ID, MEASURE_VALUE)
      FROM MY_TABLE;

【讨论】:

  • 非常感谢。现在我觉得自己很愚蠢......过去我做过很多次,但我发现这个错误有点误导,我花了几个小时调查错误的方向。谢谢!
【解决方案2】:

您只能将BULK COLLECT 对象放入对象表中。在你的情况下:

SQL> CREATE OR REPLACE TYPE hashmap_num_type_obj AS OBJECT (
  2      the_id                 NUMBER,
  3      the_value              NUMBER(10,1)
  4  );
  5  /

Type created

SQL> CREATE OR REPLACE TYPE hashmap_num_type IS TABLE OF hashmap_num_type_obj;
  2  /

Type created

SQL> DECLARE
  2     l_tab hashmap_num_type;
  3  BEGIN
  4     SELECT hashmap_num_type_obj(measure_id, measure_value)
  5       BULK COLLECT INTO l_tab
  6       FROM my_table;
  7  END;
  8  /

PL/SQL procedure successfully completed

【讨论】:

    【解决方案3】:

    我已经解决了你的问题

    declare
    type REC_TYPE is record (
                THE_ID  number,
                THE_VALUE   number
                );
    type TB_TYPE is table of REC_TYPE index by binary_integer;
    TBL TB_TYPE;
    
    cursor CURSOR_1 is 
        select  a1.MEASURE_ID A$1, a1.MEASURE_VALUE A$2
         from MY_TABLE a1;
    type REF_CUR_ is ref cursor return CURSOR_1%rowtype;
    CURSOR_2    REF_CUR_;
    begin
        open CURSOR_2 for 
             select  a1.MEASURE_ID A$1, a1.MEASURE_VALUE A$2
             from MY_TABLE a1;
        fetch CURSOR_2 bulk collect into TBL ;
        close CURSOR_2;
        return;
    end;
    

    它的作品。

    我找到了另一种没有引用光标there 的方法(寻找FETCH Statement with BULK COLLECT Clause

    【讨论】:

      【解决方案4】:

      您应该将行检索到基于记录类型而不是对象类型的类型中。以下作品;

      DECLARE
         TYPE hashmap_num_type_rt IS RECORD
             (THE_ID                 NUMBER,
              THE_VALUE              NUMBER(10,1) 
             );   
         TYPE hashmap_num_type_t IS TABLE OF hashmap_num_type_rt;
      
         stats_by_measure hashmap_num_type_t;
      
      BEGIN
        SELECT measure_id, measure_value
        BULK COLLECT INTO stats_by_measure
        FROM my_table;
      
        FOR i IN 1..stats_by_measure.COUNT
        LOOP
          DBMS_OUTPUT.PUT_LINE('RECORD '||TO_CHAR(i)||' : ID - '||stats_by_measure(i).the_id||' MeasureVal: '||TO_CHAR(stats_by_measure(i).the_value));
        END LOOP;
      END; 
      

      你也可以定义一个游标,然后根据游标的类型创建一个表类型(当然还是行类型而不是对象类型)。

      如果您想使用游标作为行类型,​​请尝试以下操作;

      DECLARE
         CURSOR c_measures IS
         SELECT measure_id, measure_value
           FROM my_table;
      
         TYPE hashmap_num_type_t IS TABLE OF c_measures%ROWTYPE;
      
         stats_by_measure hashmap_num_type_t;
      
      BEGIN
        OPEN c_measures;
        FETCH c_measures
        BULK COLLECT INTO stats_by_measure;
        CLOSE c_measures;
      
        FOR i IN 1..stats_by_measure.COUNT
        LOOP
          DBMS_OUTPUT.PUT_LINE('RECORD '||TO_CHAR(i)||' : ID - '||stats_by_measure(i).measure_id||' MeasureVal: '||TO_CHAR(stats_by_measure(i).measure_value));
        END LOOP;
      END;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-31
        • 1970-01-01
        • 2020-10-18
        • 1970-01-01
        • 1970-01-01
        • 2019-01-10
        • 1970-01-01
        相关资源
        最近更新 更多