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

mat*_*elo 5 sql oracle triggers plsql oracle11g

我在Oracle中开发Trigger时遇到了这个问题:ORA-01403:找不到数据.我做了一些研究并理解了问题的根源.尽管如此,处理错误异常可以防止上述错误,但不能解决我的问题.

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

脚本

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

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)
);
Run Code Online (Sandbox Code Playgroud)

当触发器被触发时,我将有一个DATE字段 - 比方说DATE_GIVEN(例如清酒).我需要的是:

  1. 找到DATE_REFERENCE哪一行DATE_GIVEN BETWEEN DATE_START AND DATE_END(简单); 要么
  2. 如果前一个选项没有返回数据,我需要找到下一个最接近DATE_START的数据DATE_GIVEN.

在这两种情况下,我都需要从表中检索包含所有列的行DATE_REFERENCE,无论它是否与Opt 1或2匹配.这正是我遇到所描述问题的地方.

我写了这个测试块来测试并试图找到一个解决方案.我知道,下面的例子不起作用 ; 但这正是我想要完成的(在概念上).我添加了一些评论-- Lots of code,以表明它将成为更复杂的触发器的一部分:

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;
Run Code Online (Sandbox Code Playgroud)

知道上面的PL/SQL块比工作代码更像是一个概念,获得填充,调整性能和尽可能少的查询的最佳方法是什么?RESULTROW

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

Gor*_*off 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;
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

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;
Run Code Online (Sandbox Code Playgroud)

我相信正确的条件是DATE_GIVEN <= DATE_END.这包括between条件和应该暗示DATE_GIVEN < DATE_START.这假定DATE_END永远不会NULL.