使用“SELECT INTO”时,Oracle PL / SQL - ORA-01403“未找到数据”

时间:2014-02-25 21:02:29

标签: sql oracle plsql triggers oracle11g

我在Oracle中开发Trigger时遇到了这个问题:ORA-01403: no data found。我做了一些研究并理解了问题的根源。不过handling the error exception可以防止上述错误,但无法解决我的问题。

我目前正在寻找的是最佳解决方法,以执行较少的查询量/尽可能获得最佳性能。我将尝试描述为真实结构创建简单示例的场景。

方案

我有一个“日期参考”表来确定时间段,比如说:

CREATE TABLE DATE_REFERENCE (
    DATE_START                  DATE NOT NULL,
    DATE_END                    DATE NOT NULL,
    -- Several other columns here, this is just a silly example
    CONSTRAINT PK_DATE_REFERENCE PRIMARY KEY(DATE_START, DATE_END)
);

触发触发器时,我会有一个DATE字段 - 比如DATE_GIVEN(例如清酒)。我需要的是:

  1. 查找DATE_REFERENCE行({1}}(简单); OR
  2. 如果上一个选项返回无数据,我需要找到下一个距DATE_GIVEN BETWEEN DATE_START AND DATE_END DATE_START最接近的地方。
  3. 在这两种情况下,我都需要从表DATE_GIVEN中检索包含所有列的行,无论它是否与选项1或2匹配。这正是我遇到所描述问题的地方。

    我将此测试块写入 test 并尝试找到解决方案。我知道,下面的例子不起作用; 完全我想要完成的事情(概念上)。我添加了DATE_REFERENCE之类的评论,以明确这将成为更详细的触发器的一部分:

    -- Lots of code

    问题

    知道上面的PL / SQL块比 概念 更多 工作代码 ,是什么获得DECLARE DATE_GIVEN DATE; RESULTROW DATE_REFERENCE%ROWTYPE; BEGIN -- Lots of code -- Lots of code -- Lots of code DATE_GIVEN := TO_DATE('2014-02-26 12:30:00', 'YYYY-MM-DD HH24:MI:SS'); -- This one throws the ORA-01403 exception if no data was found SELECT * INTO RESULTROW FROM DATE_REFERENCE WHERE DATE_GIVEN BETWEEN DATE_START AND DATE_END; -- If the above didn't throw exceptions, I would continue like so: IF RESULTROW IS NULL THEN SELECT * INTO RESULTROW FROM DATE_REFERENCE WHERE DATE_START > DATE_GIVEN AND ROWNUM = 1 ORDER BY DATE_START ASC; END IF; -- Now RESULTROW is populated, and the rest of the trigger code gets executed ~beautifully~ -- Lots of code -- Lots of code -- Lots of code END; 填充,管理性能和较少查询的最佳方法是什么?

    很抱歉这个问题很长,但我认为情景说明是必要的。提前感谢任何帮助/想法!

3 个答案:

答案 0 :(得分:6)

使用排序和rownum

直接填充字段
SELECT * INTO RESULTROW
FROM (SELECT *
      FROM DATE_REFERENCE
      ORDER BY (CASE WHEN DATE_GIVEN BETWEEN DATE_START AND DATE_END
                     THEN 1 ELSE 0
                END) DESC,
               (DATE_START - DATE_GIVEN)
     ) t
WHERE rownum = 1;

这将使用一个查询填充信息。

编辑:

如果要在子查询中添加条件,则需要:

SELECT * INTO RESULTROW
FROM (SELECT *
      FROM DATE_REFERENCE
      WHERE DATE_GIVEN <= DATE_END
      ORDER BY (CASE WHEN DATE_GIVEN BETWEEN DATE_START AND DATE_END
                     THEN 1 ELSE 0
                END) DESC,
               (DATE_START - DATE_GIVEN)
     ) t
WHERE rownum = 1;

我认为正确的条件是DATE_GIVEN <= DATE_END。这涵盖了between条件,并且应该隐含DATE_GIVEN < DATE_START。这假定DATE_END永远不会NULL

答案 1 :(得分:0)

我也有类似的问题,像这样解决:

如果表LADDER.INCR_PROCESS中不存在该行,我将得到IsPassed为空:

Declare    
    IsPassed      Integer ;
Begin
    Select I.LVL Into IsPassed 
      From LADDER.INCR_PROCESS  I
      Right 
      Join  Dual   on I.LVL >= 90010  and I.Passed = 0  
     Where RowNum = 1 ;
     ....
End;

答案 2 :(得分:0)

我刚刚找到了新的解决方案:

    Declare
        L_ID    Integer;
      Begin
      select 
          (  Select PREFERREDID  from ladder.ric_exceptions where  PREFERREDID  = 1 ) into  L_ID
      from dual;
      end;