風待ち

プログラミングの勉強や日々の出来事のログなど

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年、正月三が日の深夜の思い出。