ORA-01006: bind variable does not exist は、Oracleで実行時に渡したバインド変数が、実際のSQL文やPL/SQLブロック内に存在しない時に発生するエラーです。SQLには :dept_id しかないのにアプリ側で :department_id を渡している、動的SQLで条件を外したのに USING 句だけ残っている、といった状況で起きます。
Oracle公式の説明では、バインド呼び出しで参照した変数がSQL文に列挙されていないことが原因です。つまり、SQL本文にあるプレースホルダと、実行時に渡しているバインド指定の対応が崩れています。
ORA-01006が出たら、完成後のSQL全文とバインド値一覧を同時にログへ出し、SQLに存在しない名前や余分な値を渡していないか確認します。不足なら ORA-01008、名前や場所の不正なら ORA-01036 も合わせて切り分けます。
ORA-01006とは
バインド変数は、SQL内の値を :name や :1 のようなプレースホルダで表し、実行時に値だけを別途渡す仕組みです。安全性やパース効率の面では有効ですが、SQL本文と渡す値の対応がずれるとバインド系のエラーになります。
| 見る場所 | ORA-01006で起きていること | 修正の方向 |
|---|---|---|
| SQL本文 | 渡された名前のプレースホルダがない | SQLにある名前だけを渡す |
| 動的SQL | 条件を削ったのにUSING側だけ残った | SQL生成と値追加を同じ分岐にする |
| DBMS_SQL | 存在しない名前をBIND_VARIABLEしている |
パースしたSQLのプレースホルダ名へ合わせる |
| アプリ | パラメータ名のタイプミスや余分な値がある | 最終SQLとパラメータ一覧を照合する |
バインド変数の基本や性能面は Oracleバインド変数ガイド にまとめています。この記事では、ORA-01006の原因になる「SQLにないバインドを渡す」パターンに絞って解説します。
ORA-01008・ORA-01036との違い
ORA-01006は、ORA-01008やORA-01036と混同しやすいエラーです。切り分けでは、SQL本文にあるプレースホルダと、実行時に渡している値のどちらが多いか、または名前や場所が不正かを見ます。
ORA-01006
主な意味: SQLに存在しないバインド変数を渡している
例: SQLには :dept_id しかないのに :department_id を渡す
確認先: 余分なバインド、名前のタイプミス、動的SQLの条件分岐
ORA-01008
主な意味: SQL内のバインド変数に値が不足している
例: SQLに :dept_id があるのに値を渡していない
関連記事: ORA-01008
ORA-01036
主な意味: バインド変数名や番号、バインドできない場所の指定が不正
例: 表名・列名・DDLのオブジェクト名をバインドしようとしている
関連記事: ORA-01036
SQLにないバインド変数を渡している
最も単純な原因は、SQL本文にない名前を実行時に渡しているケースです。パラメータ名の変更、リファクタリング、条件分岐の追加で起きやすいです。
-- SQLにあるのは :dept_id だけ SELECT employee_id, employee_name FROM employees WHERE department_id = :dept_id; -- NG: 実行側で :department_id を渡していると対応先がない -- bind: department_id = 10
修正は、SQL側と実行側の名前をそろえることです。名前指定バインドでは、変数名の表記ゆれを減らすため、SQLを組み立てる層とパラメータを作る層で同じ定数を使うと事故が減ります。
SELECT employee_id, employee_name FROM employees WHERE department_id = :dept_id; -- OK: SQLに存在する :dept_id に値を渡す -- bind: dept_id = 10
動的SQLで条件を外したのにUSING句だけ残っている
実務で多いのは、検索条件を動的に組み立てる処理です。条件を追加しなかった時にも USING 句へ値だけ渡してしまうと、SQL内に対応するプレースホルダがないためORA-01006になります。
DECLARE
v_sql VARCHAR2(4000) := 'SELECT * FROM employees WHERE 1 = 1';
v_name VARCHAR2(100) := NULL;
v_count NUMBER;
BEGIN
IF v_name IS NOT NULL THEN
v_sql := v_sql || ' AND employee_name LIKE :name';
END IF;
-- NG: v_name がNULLならSQLに :name が存在しない
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM (' || v_sql || ')'
INTO v_count
USING v_name;
END;
/
条件を追加する分岐と、バインド値を渡す分岐は必ずセットにします。静的に分岐できる範囲なら、SQL文自体を分ける方が読みやすいこともあります。
DECLARE
v_sql VARCHAR2(4000) := 'SELECT COUNT(*) FROM employees WHERE 1 = 1';
v_name VARCHAR2(100) := NULL;
v_count NUMBER;
BEGIN
IF v_name IS NOT NULL THEN
v_sql := v_sql || ' AND employee_name LIKE :name';
EXECUTE IMMEDIATE v_sql INTO v_count USING '%' || v_name || '%';
ELSE
EXECUTE IMMEDIATE v_sql INTO v_count;
END IF;
END;
/
動的SQLでは、動的SQLのセキュアな書き方 で解説しているように、値はバインド変数、列名や表名などSQL構造は許可リストや DBMS_ASSERT で扱うのが基本です。
同じプレースホルダ名を複数回使う場合
動的SQLでは、同じ名前のプレースホルダを複数回書いた時の扱いにも注意します。通常のSQL文では出現回数ぶんの値を USING へ渡します。一方、匿名PL/SQLブロックや CALL 文では、同じ名前は1つのバインド変数として扱われます。この違いを混同すると、値が足りない場合はORA-01008、余分な値や対応しない名前を渡す場合はORA-01006系の原因になります。
DECLARE
v_sql VARCHAR2(4000);
v_dept NUMBER := 10;
v_cnt NUMBER;
BEGIN
v_sql := 'SELECT COUNT(*)
FROM employees
WHERE department_id = :x
OR manager_id = :x';
-- SQL文では :x が2回出ているので、値も2回渡す
EXECUTE IMMEDIATE v_sql INTO v_cnt USING v_dept, v_dept;
END;
/
DECLARE v_block VARCHAR2(4000); v_dept NUMBER := 10; BEGIN v_block := 'BEGIN update_dept(:x, :x); END;'; -- PL/SQLブロックでは同じ名前 :x は1つの値に対応する EXECUTE IMMEDIATE v_block USING v_dept; END; /
迷った時は、実行している文字列が「SQL文」なのか「匿名PL/SQLブロック」なのかを先に分けます。BEGIN ... END; で包んでいる場合はPL/SQLブロックとして扱われるため、通常のSQL文とは数え方が変わります。
OPEN FORのUSING句がSQL本文と合っていない
REF CURSORを返す処理でも同じです。OPEN cursor FOR sql USING ... では、SQL本文にあるプレースホルダに対応する値だけを USING に渡します。
DECLARE TYPE rc IS REF CURSOR; c rc; v_sql VARCHAR2(4000) := 'SELECT * FROM employees'; v_dept NUMBER := 10; BEGIN -- NG: SQLに :dept_id がないのに v_dept を渡している OPEN c FOR v_sql USING v_dept; END; /
DECLARE TYPE rc IS REF CURSOR; c rc; v_sql VARCHAR2(4000) := 'SELECT * FROM employees WHERE department_id = :dept_id'; v_dept NUMBER := 10; BEGIN OPEN c FOR v_sql USING v_dept; END; /
DBMS_SQL.BIND_VARIABLEの名前が間違っている
DBMS_SQL を使う場合は、PARSE したSQL内のプレースホルダ名と、BIND_VARIABLE で指定する名前を合わせます。SQLにない名前を指定すると、ORA-01006の原因になります。
DECLARE
c INTEGER;
n INTEGER;
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(
c,
'SELECT * FROM employees WHERE department_id = :dept_id',
DBMS_SQL.NATIVE
);
-- NG: SQLには :department_id が存在しない
DBMS_SQL.BIND_VARIABLE(c, ':department_id', 10);
n := DBMS_SQL.EXECUTE(c);
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
DBMS_SQL.BIND_VARIABLE(c, ':dept_id', 10);
JDBCやPythonなどアプリ側で起きる場合
アプリから実行する場合は、最終的に送るSQLとパラメータの名前をログで並べて確認します。フレームワークやドライバによっては同じ状況が ORA-01036 として出ることもありますが、切り分けの基本は「SQLにある名前だけを渡す」です。
sql = """
SELECT employee_id, employee_name
FROM employees
WHERE department_id = :dept_id
"""
# NG: SQLにない department_id を渡している
cursor.execute(sql, {"department_id": 10})
# OK
cursor.execute(sql, {"dept_id": 10})
String sql = "SELECT employee_id FROM employees WHERE department_id = :dept_id";
// 名前付きパラメータを扱うラッパーを使う場合、SQL側の名前と一致させる
params.put("dept_id", 10);
// department_id のような別名を渡すと、SQL側に対応先がない
調査手順
ORA-01006は、完成後のSQLとバインド一覧を見ればかなり早く切り分けられます。ソースコード上の断片ではなく、条件分岐や文字列連結が終わった後のSQLを確認してください。
| 順番 | 確認すること | 見るポイント |
|---|---|---|
| 1 | 完成後のSQLをログに出す | :name、:1 の出現を確認する |
| 2 | 渡しているバインド一覧を出す | SQLにない名前や余分な値がないか見る |
| 3 | 条件分岐を確認する | SQL追加と値追加が同じ条件で動くか見る |
| 4 | ORA-01008と分ける | 不足なのか、余分なのかを分ける |
| 5 | ORA-01036と分ける | 表名・列名・DDLなど、バインドできない場所でないか見る |
チェックリスト
- 完成後のSQL全文を確認した
- SQL内のプレースホルダ名と実行時パラメータ名が一致している
- 動的SQLで、条件追加とバインド値追加が同じ分岐にある
- SQLにない余分なパラメータを渡していない
DBMS_SQL.BIND_VARIABLEの名前がSQL本文と一致している- 値はバインド変数、表名・列名は許可リストで扱っている
- 不足ならORA-01008、名前/場所の不正ならORA-01036として切り分けた
よくある質問
ORA-01006とORA-01008は何が違いますか?
ORA-01006は、SQLに存在しないバインド変数を渡している状態です。ORA-01008は、SQLに存在するバインド変数へ値が不足している状態です。値が多い・名前が余っているならORA-01006、不足しているならORA-01008を疑います。
同じSQLなのに環境でだけ発生します
SQL生成の条件分岐、アプリ設定、検索条件の有無、ドライバのバージョン差で、最終SQLや渡すパラメータが変わっている可能性があります。エラー時のSQL全文とバインド一覧を同じログに出してください。
表名や列名をバインドできますか?
通常、表名や列名などSQL構造はバインド変数では置き換えません。値はバインド変数、SQL構造は許可リストで選択し、必要に応じてDBMS_ASSERTで検証します。
まとめ
ORA-01006は、SQLに存在しないバインド変数を実行時に渡している時に発生します。完成後のSQL本文とバインド一覧を照合し、余分な名前、タイプミス、動的SQLの条件分岐ずれを確認しましょう。
不足ならORA-01008、バインド名や場所の不正ならORA-01036と切り分けると、原因を早く絞れます。動的SQLでは、SQL文字列とバインド値を同じ分岐で組み立てるのが安全です。
参考
ORA-01006 – Oracle Database Error Help
PL/SQL Dynamic SQL – Oracle Database PL/SQL Language Reference

