0

我已经寻找了一段时间来寻找解决这个问题的方法,我发现的所有 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子句。

4

2 回答 2

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

于 2012-09-18T20:27:45.817 回答
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 插入空值(如果全部为空)

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

于 2012-09-18T20:23:48.327 回答