PL/SQL の触り始めに苦労するのが、エラー文の癖の強さです。
PL/SQL 自体が一般的なプログラミング言語と構文の感覚が違っていることもあって、慣れるまではエラーを出力されても間違いがどこにあるのか判りづらい…。
中でも地味に、しかし頻繁に時間を奪われるのが細かいエラーへの対処。
誤字やセミコロンの付け間違いのようなうっかりミスで、総合してどれだけの時間を奪われたことか。
この記事では、そういうしょぼい例を列挙していきます。
環境
- Oracle 11g
- SQL Developer
- 日本語環境
事例
IF
文のあたりでエラーがある
???
BEGIN
IF TRUE THEN
DBMS_OUTPUT.PUT_LINE('Hello!');
END;
END;
/
ORA-06550: 行4、列6:
PLS-00103: 記号";"が見つかりました。 次のうちの1つが入るとき:
if
記号"if" は続行のために";"に代わりました。
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
!!!
IF
を閉じるときは END IF
。
BEGIN
IF TRUE THEN
DBMS_OUTPUT.PUT_LINE('Hello!');
END IF;
END;
/
IF
文のあたりでエラーがある 2
???
BEGIN
IF TRUE THEN
-- あとで書く
END IF;
END;
/
ORA-06550: 行4、列3:
PLS-00103: 記号"END"が見つかりました。 次のうちの1つが入るとき:
( begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
!!!
IF
文の中になんでもいいから処理を書く。
ちなみに BEGIN
~ END
も同様。
BEGIN
IF TRUE THEN
-- あとで書く
NULL;
END IF;
END;
/
NULL
は何もしない処理。
見えないものが見えると言われ、無視していないものを無視していると詰め寄られる
?
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello!');
END;
/
ORA-06550: 行2、列3:
PLS-00103: 記号""が見つかりました。 次のうちの1つが入るとき:
( begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
記号"" は無視されました。
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
!
インデントが全角スペースだった。
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello!');
END;
/
関数がうまくコンパイルされない
???
CREATE OR REPLACE PROCEDURE proc1
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('in proc1');
END proc1;
BEGIN
proc1;
END;
/
Error(6,1): PLS-00103: 記号"BEGIN"が見つかりました。
!!!
プロシージャ定義の後にスラッシュが抜けてた。
CREATE OR REPLACE PROCEDURE proc1
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('in proc1');
END proc1;
/
BEGIN
proc1;
END;
/
関数がうまくコンパイルされない 2
???
CREATE OR REPLACE PROCEDURE coolProc()
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('in coolProc');
END coolProc;
/
BEGIN
coolProc();
END;
/
Error: PLS-00103: 記号")"が見つかりました。 次のうちの1つが入るとき: <an identifier> <a double-quoted delimited-identifier> current delete exists prior
!!!
引数なし関数を定義するときに括弧を付けてはいけない。
CREATE OR REPLACE PROCEDURE coolProc
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('in coolProc');
END coolProc;
/
BEGIN
coolProc();
END;
/
呼び出すときは括弧を付けてもいい。
関数がうまくコンパイルされない 3
???
CREATE OR REPLACE PROCEDURE writePrefix(
text VARCHAR2
)
IS
prefix VARCHAR2;
BEGIN
prefix := SUBSTR(text, 1, 1);
DBMS_OUTPUT.PUT_LINE(text || 'の接頭辞は' || prefix);
END writePrefix;
/
BEGIN
writePrefix('テキスト');
END;
/
ORA-06550: 行2、列3:
PLS-00905: オブジェクト'TESTUSER.WRITEPREFIX'が無効です。
ORA-06550: 行2、列3:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Error(3,10): PLS-00215: 文字列の長さは制約範囲内(1から32767)である必要があります
!!!
引数の場合、長さの設定が必要な型でも設定は禁止だが、それ以外の変数では長さの設定が必要。
CREATE OR REPLACE PROCEDURE writePrefix(
text VARCHAR2
)
IS
prefix VARCHAR2(3);
BEGIN
prefix := SUBSTR(text, 1, 1);
DBMS_OUTPUT.PUT_LINE(text || 'の接頭辞は' || prefix);
END writePrefix;
/
BEGIN
writePrefix('テキスト');
END;
/
ファンクションまわりでなんかおかしい
???
CREATE OR REPLACE FUNCTION func1
RETURN NUMBER
IS
BEGIN
RETURN(1);
END func1;
/
BEGIN
func1;
END;
/
ORA-06550: 行2、列3:
PLS-00221: 'FUNC1'がプロシージャではないか、または未定義です。
ORA-06550: 行2、列3:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
!!!
ファンクションの戻り値は、呼び出し側で受け取る必要がある。
CREATE OR REPLACE FUNCTION func1
RETURN NUMBER
IS
BEGIN
RETURN(1);
END func1;
/
DECLARE
n NUMBER;
BEGIN
n := func1;
END;
/
パッケージの定義がうまくいかない
???
CREATE OR REPLACE PACKAGE package1
IS
PROCEDURE proc1(text VARCHAR2);
END package1;
/
CREATE OR REPLACE PACKAGE BODY package1
IS
PROCEDURE proc1(text VARCHAR2);
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(text);
END proc1;
END package1;
/
BEGIN
package1.proc1('テキスト');
END;
/
Error(3,3): PLS-00103: 記号"IS"が見つかりました。 次のうちの1つが入るとき: begin end function pragma procedure subtype type <an identifier> <a double-quoted delimited-identifier> current cursor delete exists prior
Error(7,5): PLS-00103: 記号"PACKAGE1"が見つかりました。 次のうちの1つが入るとき: ;
!!!
PACKAGE BODY
内のプロシージャの引数定義直後にセミコロンが入ってた。
CREATE OR REPLACE PACKAGE package1
IS
PROCEDURE proc1(text VARCHAR2);
END package1;
/
CREATE OR REPLACE PACKAGE BODY package1
IS
PROCEDURE proc1(text VARCHAR2)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(text);
END proc1;
END package1;
/
BEGIN
package1.proc1('テキスト');
END;
/
パッケージの定義がうまくいかない 2
???
CREATE OR REPLACE PACKAGE package1
IS
PROCEDURE proc1(
description VARCHAR2
);
END package1;
/
CREATE OR REPLACE PACKAGE BODY package1
IS
PROCEDURE proc1(
text VARCHAR2
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(text);
END proc1;
END package1;
/
Error(2,13): PLS-00323: パッケージ仕様部で未定義のサブプログラムまたはカーソルPROC1が宣言されています。
!!!
PACKAGE
と PACKAGE BODY
の関数定義で、違う引数名を使ってはいけない。
CREATE OR REPLACE PACKAGE package1
IS
PROCEDURE proc1(
description VARCHAR2
);
END package1;
/
CREATE OR REPLACE PACKAGE BODY package1
IS
PROCEDURE proc1(
description VARCHAR2
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(description);
END proc1;
END package1;
/
オーバーライドがうまくいかない
???
CREATE OR REPLACE PACKAGE package1
IS
PROCEDURE proc1(
rec EXAMPLE_WORK%ROWTYPE
);
PROCEDURE proc1(
rec EXAMPLE_EMPLOYEE%ROWTYPE
);
END package1;
/
CREATE OR REPLACE PACKAGE BODY package1
IS
PROCEDURE proc1(
rec EXAMPLE_WORK%ROWTYPE
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(rec.WORK_NAME);
END proc1;
PROCEDURE proc1(
rec EXAMPLE_EMPLOYEE%ROWTYPE
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(rec.EMPLOYEE_NAME);
END proc1;
END package1;
/
BEGIN
FOR rec IN (
SELECT * FROM EXAMPLE_WORK
) LOOP
package1.proc1(rec);
END LOOP;
END;
/
ORA-06550: 行5、列5:
PLS-00307: このコールに一致する'PROC1'が複数宣言されています。
ORA-06550: 行5、列5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
!!!
テーブルの列構造が同じ。
- EXAMPLE_WORK
COLUMN_NAME | DATA_TYPE |
---|---|
ID | NUMBER |
WORK_NAME | VARCHAR(20) |
- EXAMPLE_EMPLOYEE
COLUMN_NAME | DATA_TYPE |
---|---|
ID | NUMBER |
WORK_NAME | VARCHAR(100) |
%ROWTYPE
や FOR
で扱う行オブジェクトは、テーブルの列構造のみを真似る。テーブルの名前や制約等の情報はもたない。
実行環境によっては、列構造かぶりのオーバーライドでもエラーを吐かずに実行可能だが、その場合は先に定義した方の関数がしれっと実行される。
テーブルの値をうまく処理できない
???
DECLARE
TYPE EXAMPLE_EMPLOYEE_TYPE IS RECORD(
EMPLOYEE_NAME VARCHAR(20)
,ID NUMBER(20)
);
CURSOR cur
IS
SELECT
*
FROM
EXAMPLE_EMPLOYEE
;
employee_rec EXAMPLE_EMPLOYEE_TYPE;
BEGIN
OPEN cur;
LOOP
FETCH cur INTO employee_rec;
EXIT WHEN cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(
'name: ' || employee_rec.EMPLOYEE_NAME);
END LOOP;
CLOSE cur;
END;
/
ORA-06502: PL/SQL: 数値または値のエラー: 文字から数値への変換エラー。が発生しました
ORA-06512: 行19
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
!!!
テーブル EXAMPLE_EMPLOYEE
と型 EXAMPLE_EMPLOYEE_TYPE
の列の並びが違う。
- EXAMPLE_EMPLOYEE
COLUMN_NAME | DATA_TYPE | COLUMN_ID |
---|---|---|
ID | NUMBER | 1 |
EMPLOYEE_NAME | VARCHAR(100) | 2 |