PL/SQLでSELECT INTOをした時にORA-01422が出る場合には、一度、引数とか変数の名前をカラム名と同じにしていないか確認しよう。
ORA-01422がでるのは、PL/SQLで変数にどこかのテーブルの値を検索してセットする時なんかに、戻ってくる値が一意にならないからエラーになる。
例えば下記のようにするとエラーになる。
CREATE OR REPLACE PROCEDURE SAMPLE ( USER_ID IN NUMBER ) AS V_USER_NAME VARCHAR2(32 CHAR) BEGIN SELECT USER_NAME INTO V_USER_NAME FROM USERS WHERE USER_ID = USER_ID; DBMS_OUTPUT.PUT_LINE('USER_NAME: ' || V_USER_NAME); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('ERROR CODE: ' || SQLCODE || ', MESSAGE: ' || SQLERRM); END; END;
この場合、引数のUSER_IDとUSERSテーブルのカラム名のUSER_IDがまったく同じなので、エラーになる。
例えば、引数のUSER_IDを「SAMPLE」にするとWHERE句が「'SAMPLE' = 'SAMPLE'」となり、まったく同じ値で比較してしまう。
これだとUSERSテーブルのすべてが返ってきてしまうので、V_USER_NAMEに何をセットしたらいいかわからなくて、ORA-01422が出てしまう。
SELECT USER_NAME INTO USER_NAME FROM USERS WHERE 'SAMPLE' = 'SAMPLE';
それを回避するには、単に引数名や変数名をカラム名と同じにしなければいい。
引数は「P_(アンダーバー)」で始め、変数は「V_(アンダーバー)」で始めれば区別もついてわかりやすいと思う。
上のコードの引数の部分を書き換えて、P_USER_IDにすれば問題なく動いてくれる。
CREATE OR REPLACE PROCEDURE SAMPLE ( P_USER_ID IN NUMBER ) AS V_USER_NAME VARCHAR2(32 CHAR) BEGIN SELECT USER_NAME INTO V_USER_NAME FROM USERS WHERE USER_ID = P_USER_ID; DBMS_OUTPUT.PUT_LINE('USER_NAME: ' || V_USER_NAME); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('ERROR CODE: ' || SQLCODE || ', MESSAGE: ' || SQLERRM); END; END;
当初はエラーを出力していなかったので、なんでこけるのかわからず、無駄な時間を過ごした。
2018年、正月三が日の深夜の思い出。