使用Select Into MULTIPLE变量处理NO_DATA_FOUND异常

时间:2012-09-18 19:59:57

标签: sql oracle

我现在已经找了一段时间来解决这个问题,我发现的所有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临时结果集的前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子句。

2 个答案:

答案 0 :(得分:2)

好的,我想我能帮到你;您的大部分问题都是由于错误地嵌套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中有一行,那么将设置每个变量,因此无需尝试处理此问题。

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,那么我会这样做。你似乎没有任何额外的逻辑,所以它应该是可能的。

答案 1 :(得分:1)

  

然而,三个中的一个通常是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插入空值(如果所有都为null)

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的数据,则不插入任何内容。如果至少其中一个不为null,则插入这些值。