web-dev-qa-db-ja.com

PL / SQL selectの結果ごとに1行を挿入

入力変数に基づいて選択を実行し、選択の各結果に行を挿入するPL/SQLプロシージャを作成しています。 PL/SQLが新しくなったため、クエリの何が問題なのかをデバッグできません。これは簡単でなければならないことは知っていますが、何らかの理由でここで立ち往生しています。ご協力いただきありがとうございます!

CREATE OR REPLACE PROCEDURE setup_name_map(ranking_id IN NUMBER, class_string IN VARCHAR2) 
IS
BEGIN

    FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES WHERE NAME = class_string)
    LOOP
        EXECUTE IMMEDIATE 'INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID) VALUES (' || rec.NAME_ID || ', ' || ranking_id || ')';
    END LOOP;
END;

Oracle Developer Compilerによると... 'NAME_ID'は無効な識別子です。私は引用符でそれを入れてみましたが、サイコロはしませんでした。また、ループインデックス変数 'REC'の使用が無効であるという不満もあります。どんな助けも大歓迎です。

17
Craig

ここでは動的SQLの必要はありません。

BEGIN

    FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES
                WHERE NAME = class_string)
    LOOP
        INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID)
        VALUES (rec.NAME_ID, ranking_id);
    END LOOP;
END;

さらに良いのは、次のような遅い行ごとのカーソルアプローチを回避できることです。

BEGIN
    INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID)
    SELECT NAME_ID, ranking_id FROM PRODUCT_NAMES
    WHERE NAME = class_string;
END;

本当に動的SQLが必要な場合は、値を連結するのではなく、バインド変数を使用する必要があります。

BEGIN

    FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES
                WHERE NAME = class_string)
    LOOP
        EXECUTE IMMEDIATE 'INSERT INTO NAME_RANKING 
                           (NAME_ID, RANKING_ID) VALUES (:b1, :b2)
        USING rec.NAME_ID, ranking_id;
    END LOOP;
END;
48
Tony Andrews