【问题标题】:NO_DATA_FOUND exception handling with Select Into MULTIPLE variables使用 Select Into MULTIPLE 变量处理 NO_DATA_FOUND 异常
【发布时间】:2012-09-18 19:59:56
【问题描述】:

我已经寻找了一段时间来解决这个问题,我发现的所有 NO_DATA_FOUND 处理教程都只显示了在一个变量中只有一列的 Select Into 时如何做到这一点。

首先,这是我的代码:

BEGIN 
    OPEN c_no_source; 
    LOOP 
        DECLARE 
            l_price_code  VARCHAR2(20) := ''; 
            l_price_level VARCHAR(10) := ''; 
            l_code_date   DATE := p_effective_date; 
        BEGIN 
            FETCH c_no_source INTO c_no_source_row;
                exit WHEN c_no_source%NOTFOUND;
            BEGIN 
                WITH codeList AS /* liste des dates ayant une donnée avant la date effective incluse. */
                (
                    SELECT distinct
                        NVL(effective_date,p_effective_date) as effective_date,
                        NVL(user_group2,'') as price_code, 
                        NVL(user_group3,'') as price_level
                    FROM  DGA_Service.Hjvsecmaster_Hist
                    WHERE   effective_date <= p_effective_date
                        AND user_group2 IS NOT NULL
                        AND security_alias = c_no_source_row.security_alias
                    ORDER BY 1 DESC
                )
                SELECT price_code, price_level, effective_date 
                INTO   l_price_code, l_price_level, l_code_date 
                FROM   codelist 
                WHERE  ROWNUM = 1; 
                EXCEPTION WHEN no_data_found THEN NULL;

                ...
                [UPDATE statement using the variables] 
                ...
            END; 
        END; 
    END LOOP; 

    CLOSE c_no_source; 
END; 

我想要做的是将我的codeList temp 结果集的前 1 个结果放入三个单独的变量中。 但是codeList 中的三列之一通常是NULL。我的 3 个变量都不会设置。 我试图处理异常,但我无法让我的代码将具有值的列插入到它们各自的变量中。如果即使其中一列是 NULL,那么它们都不会插入到它们的变量中。

我希望 Select Into 语句设置它可以设置的变量。

我尝试使用以下方法分别处理它们:

EXCEPTION WHEN NO_DATA_FOUND THEN
    BEGIN
        IF price_code IS NOT NULL THEN l_price_code := price_code; END IF;
        IF price_level IS NOT NULL THEN l_price_level := price_level; END IF;
        IF effective_date IS NOT NULL THEN l_code_date := effective_date; END IF;
    END;

但我收到以下错误消息:

ORA-06550: line 294, column 18:
PLS-00201: identifier 'PRICE_CODE' must be declared
ORA-06550: line 294, column 15:
PL/SQL: Statement ignored
ORA-06550: line 295, column 18:
PLS-00201: identifier 'PRICE_LEVEL' must be declared
ORA-06550: line 295, column 15:
PL/SQL: Statement ignored
ORA-06550: line 296, column 18:
PLS-00201: identifier 'EFFECTIVE_DATE' must be declared
ORA-06550: line 296, column 15:
PL/SQL: Statement ignored

所以我的想法用完了。我尝试指定临时表名称,但无济于事,如下所示:

IF codeList.price_code IS NOT NULL

我很想在这个问题上提供任何帮助。这段代码运行的包已经很重了,我不想让每一列都有一个单独的With ... As () Select Into 子句。

【问题讨论】:

  • @Ben 在第一个原始代码块中,如果抛出异常,我将执行 NULL。最常见的情况是 codeList 表有 5 到 10 行,但每行将有 3 列 NULL 之一。我认为这是NO_DATA_FOUND 错误,因为当我刚刚使用EXCEPTION WHEN no_data_found THEN NULL; 时,我的3 个变量都没有设置,即使其中2 个应该设置。我可能弄错了,在这种情况下,我不知道为什么我的变量没有设置为具有值的列。
  • 我想要的只是找到一种方法来抓取循环中的每一行并设置我有值的任何变量,然后用 '' 设置其他变量。

标签: sql oracle


【解决方案1】:

好的,我想我明白了;您的大部分问题是由错误地嵌套 PL/SQL 块引起的。

您的更新语句包含在 EXCEPTION 块中,这意味着只有在抛出异常时才会执行它。其次,您在以下内容中直接引用

EXCEPTION WHEN NO_DATA_FOUND THEN
    BEGIN
        IF price_code IS NOT NULL THEN l_price_code := price_code; END IF;
        IF price_level IS NOT NULL THEN l_price_level := price_level; END IF;
        IF effective_date IS NOT NULL THEN l_code_date := effective_date; END IF;
    END;

这是编译错误的原因。

最后,如果您的 select into 中有一行,那么 every 变量将被设置,因此无需尝试处理此问题。

BEGIN 
    OPEN c_no_source; 
    LOOP 
        DECLARE 
            l_price_code  VARCHAR2(20); 
            l_price_level VARCHAR(10); 
            l_code_date   DATE := p_effective_date; 
        BEGIN 
            FETCH c_no_source INTO c_no_source_row;
                exit WHEN c_no_source%NOTFOUND;
            BEGIN 
                WITH codelist AS (
                 SELECT DISTINCT effective_date
                      , user_group2 AS price_code
                      , user_group3 AS price_level 
                   FROM hjvsecmaster_hist 
                   WHERE effective_date <= p_effective_date 
                     AND user_group2 IS NOT NULL 
                     AND security_alias = c_no_source_row.security_alias 
                   ORDER BY 1 DESC
                ) 
                SELECT price_code, price_level, effective_date 
                INTO   l_price_code, l_price_level, l_code_date 
                FROM   codelist 
                WHERE  ROWNUM = 1; 
                EXCEPTION WHEN no_data_found THEN
                   -- All variables are their initial setting
                   null;
            END; 
           ...
              [UPDATE statement using the variables] 
           ...
        END; 
    END LOOP; 

    CLOSE c_no_source; 
END; 

这通常是一种非常低效的方法。如果您可以将所有内容放入单个 UPDATE 或 MERGE 中,那么我会这样做。你似乎没有任何额外的逻辑,所以它应该是可能的。

【讨论】:

  • 完美,谢谢。我忘记将 UPDATE 语句从异常块中取出来是个笨蛋。是的,我只是将异常处理设置为NULL,一切都很好。
  • 如何将所有这些整合到更新声明中?我正在研究使用 MERGE 的解决方案。
  • @EplusL,我不确定:-)。我没有您原来的光标选择或更新语句。如果您发布所有 3 个新问题,我相信有人可以提供帮助!
  • 我找到了一个解决方案,但它很复杂,因为我必须在 with 内的选择中添加一个额外的列并进行一些奇怪的连接。另外,由于 with 子句非常快,与我必须添加整个光标位之前相比,我在此版本中的代码在性能方面仍然不受影响。生成 8000 行可能需要 4 秒而不是 3.5 秒,这是一个日常流程,客户习惯于执行其他流程大约 1 分钟的时间。感谢您的帮助。
【解决方案2】:

但是,这三个中的一个通常为 NULL,并触发 NO_DATA_FOUND 错误,我的 3 个变量都不会设置

NO_DATA_FOUND 在查询未返回任何 时引发。它与列值无关。它们都可以为空,并且语句会成功。

EXCEPTION WHEN NO_DATA_FOUND THEN
    BEGIN
        IF price_code IS NOT NULL THEN l_price_code := price_code; END IF;
        IF price_level IS NOT NULL THEN l_price_level := price_level; END IF;
        IF effective_date IS NOT NULL THEN l_code_date := effective_date; END IF;
    END;

您的变量以“l_”为前缀,并且您在比较中使用了列名 eg.price_code,因此出现了错误。 更重要的是,NO_DATA_FOUND 意味着所有的变量值都是空的,所以这个异常块不会做任何事情。

您可能只需要这个。

如果您不想为给定的 id 插入空值(如果全部为空)

BEGIN
   insert into target_table (id, col1, col2, col3)
   select id, col1, col2, col3
     from (target_table)
     where not (col1 is null and col2 is null and col3 is null);
   commit;
end;
/

如果给定 id 没有数据,则不插入任何内容。如果其中至少一个不为空,则插入这些值。

【讨论】:

    猜你喜欢
    • 2016-09-29
    • 1970-01-01
    • 2019-10-08
    • 1970-01-01
    • 1970-01-01
    • 2011-07-31
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多