0

私はこの問題の解決策をしばらく探していましたが、見つけたすべてのNO_DATA_FOUND処理チュートリアルは、1つの変数に1つの列のみを使用してSelectIntoを実行する場合の方法のみを示しています。

まず、私のコードは次のとおりです。

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つの結果を3つの別々の変数に入れることです。ただし、の3つの列の1つcodeListは多くの場合NULLです。そして、私の3つの変数はどれも設定されません。例外を処理しようとしましたが、値を持つ列をそれぞれの変数に挿入するコードを取得できません。列の1つでも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;

これがコンパイルエラーの原因です。

最後に、に1つの行がある場合は、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

ただし、3つのうちの1つがNULLになることが多く、NO_DATA_FOUNDエラーがトリガーされ、3つの変数のいずれも設定されません。

NO_DATA_FOUNDは、クエリが行を返さない場合に発生します。列の値とは何の関係もありません。それらはすべてnullである可能性があり、ステートメントは成功します。

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は、すべての変数値がnullであることを意味するため、この例外ブロックは何もしません。

おそらく必要なのはこれだけです。

特定のIDにnull値を挿入したくない場合(すべてが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のデータがない場合、何も挿入されません。それらの少なくとも1つがnullでない場合、これらの値が挿入されます。

于 2012-09-18T20:23:48.327 に答える