PL/SQL: ORA-01403 为复杂集合设置值时找不到数据

PL/SQL: ORA-01403 No data found when setting values to complex collection

我正在努力为循环中的特定限制添加小时数。我想设置从游标 c_hour 到集合 t_limits_in_plan 的值(对于当前 limit_id ), 但我在下面的循环中做错了。

我收到 ORA-01403 No data found 错误,但是 dbms_output.put_line 部分正在返回值,所以有是为 limit

指定的小时数

我不确定我是否可以解释清楚,所以我会展示。我有这样的功能

    CREATE OR REPLACE FUNCTION testFunction (p_tLimits t_limit) 
    RETURN t_limits_in_plan IS
    
    tLimitsInPlan t_limits_in_plan;
    tLimits       t_limit;
    nLimitId      number;

    
    CURSOR c_hour(LimitID number) IS
                                 SELECT *
                                   FROM hours h
                                  WHERE h.limit_id= LimitID;                 
    
  BEGIN
    tLimits := p_tLimits;
    
    FOR i IN tLimits.FIRST .. tLimits.LAST
    LOOP  
      nLimitId := tLimits(i).id;

      FOR r_hour IN c_hour(nLimitId)
      LOOP
        --I CANNOT MAKE THIS PART TO WORK 
       LimitsInPlan(tLimitsInPlan.last).hour_period_data(NVL(tLimitsInPlan(tLimitsInPlan.last).hour_period_data.last, 0) + 1).hour_from := r_hour.hour_from;
        tLimitsInPlan(tLimitsInPlan.last).hour_period_data(tLimitsInPlan(tLimitsInPlan.last).hour_period_data.last).hour_to               := r_hour.hour_to;
        dbms_output.put_line('Limit ' || nLimitId || '. Hours: ' || r_hour.hour_from || ' - ' || r_hour.hour_to);
      END LOOP;
    
    END LOOP;
    RETURN tLimitsInPlan;
  END testFunction;

我使用的类型是

  TYPE r_limits_in_plan IS RECORD (limit_in_plan_id     number
                                  ,limit                r_limit
                                  ,hour_period_data     t_hour_period_data_tab 
                                  );
 
  TYPE t_limits_in_plan IS TABLE OF r_limits_in_plan INDEX BY binary_integer;                      
  -----------------------------------------------------------------------------------   
  TYPE r_limit IS RECORD(limit_id   number
                        ,ind        varchar2(400)
                        );
    
  TYPE t_limit IS TABLE OF r_limit INDEX BY binary_integer;  
  -----------------------------------------------------------------------------------
  TYPE t_hour_period_data IS RECORD(hour_from  number
                                   ,hour_to    number);  
                           
  TYPE t_hour_period_data_tab IS TABLE OF t_hour_period_data INDEX BY binary_integer;

编辑:

I'm passing below Limit IDs to this functions
Limit ID: 26
Limit ID: 41
Limit ID: 81

So result that I'm expecting is
For LimitID 26 hours 2-3 / 12-15 / 20-23
            41 hours 5-7
            81 no hours

小时内的样本数据table

CREATE TABLE hours
(
  hour_from NUMBER not null,
  hour_to   NUMBER not null,
  limit_id  NUMBER(17) not null
)  


INSERT INTO hours (hour_from, hour_to, limit_id) VALUES (12, 13, 23);
INSERT INTO hours (hour_from, hour_to, limit_id) VALUES (2, 3, 26);
INSERT INTO hours (hour_from, hour_to, limit_id) VALUES (12, 15, 26);
INSERT INTO hours (hour_from, hour_to, limit_id) VALUES (20, 23, 26);
INSERT INTO hours (hour_from, hour_to, limit_id) VALUES (5, 7, 41);

有人能帮忙吗?我想我添加了所有需要的信息,但如果有什么需要澄清的,我会更新

最简单的解决方案是使用 SQL 定义的嵌套 table 集合和对象(而不是 PL/SQL 定义的关联数组集合和记录)传递数据,然后您可以在一个查询中完成所有处理:

CREATE TYPE r_limit IS OBJECT(
   column1    number
  ,column2    varchar2(400)
  ,column3    varchar2(400)
  ,column4    number
);
    
CREATE TYPE t_limit IS TABLE OF r_limit;

CREATE TYPE t_hour_period_data IS OBJECT(
   hour_from  number
  ,hour_to    number
);
                           
CREATE TYPE t_hour_period_data_tab IS TABLE OF t_hour_period_data;

CREATE TYPE r_limits_in_plan IS OBJECT(
   column1              number
  ,column2              varchar2(400)
  ,column3              varchar2(400)
  ,column4              varchar2(400)
  ,limit                r_limit
  ,hour_period_data     t_hour_period_data_tab 
);
 
CREATE TYPE t_limits_in_plan IS TABLE OF r_limits_in_plan;

您可以将函数定义为:

CREATE FUNCTION testFunction (p_tLimits t_limit) 
RETURN t_limits_in_plan
IS
  tLimitsInPlan t_limits_in_plan;
BEGIN
  SELECT r_limits_in_plan(
           l.column1,
           l.column2,
           l.column3,
           l.column4,
           VALUE(l),
           ( SELECT CAST(
                      COLLECT(
                        t_hour_period_data(
                          h.hour_from,
                          h.hour_to
                        )
                      ) AS t_hour_period_data_tab
                    )
             FROM   hours h
             WHERE  l.column1 = h.limit_id
           )
         )
  BULK COLLECT INTO tLimitsInPlan
  FROM   TABLE(p_tLimits) l;

  RETURN tLimitsInPlan;
END testFunction;
/

然后:

DECLARE
  v_limits t_limit := t_limit(
                        r_limit(26, '26 - Col2', '26 - Col3', 26.4),
                        r_limit(41, '41 - Col2', '41 - Col3', 41.4),
                        r_limit(81, '81 - Col2', '81 - Col3', 81.4)
                      );
  v_lip t_limits_in_plan;
BEGIN
  v_lip := testFunction(v_limits);
  FOR i IN 1 .. v_lip.COUNT LOOP
    DBMS_OUTPUT.PUT( v_lip(i).column1 || ': ' );
    
    FOR j IN 1 .. v_lip(i).hour_period_data.COUNT LOOP
      DBMS_OUTPUT.PUT( v_lip(i).hour_period_data(j).hour_from || '-' );
      DBMS_OUTPUT.PUT( v_lip(i).hour_period_data(j).hour_to || ' / ' );
    END LOOP;
    DBMS_OUTPUT.NEW_LINE();
  END LOOP;
END;
/

输出:

26: 2-3 / 12-15 / 20-23 / 
41: 5-7 / 
81: 

db<>fiddle here