我在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
(例如清酒)。我需要的是:
DATE_REFERENCE
行({1}}(简单); OR DATE_GIVEN BETWEEN DATE_START AND DATE_END
DATE_START
最接近的地方。在这两种情况下,我都需要从表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;
填充,管理性能和较少查询的最佳方法是什么?
很抱歉这个问题很长,但我认为情景说明是必要的。提前感谢任何帮助/想法!
答案 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;