ORA-01461: can bind a LONG value only for insert into a LONG column は、Oracleで長い文字列やLOB相当の値をバインドした時に、列の型や最大長と合わない場合に発生するエラーです。古いメッセージでは LONG と表示されますが、実務では VARCHAR2 列へ4000バイトを超える値を入れようとした時にもよく見ます。
Oracle公式の新しい説明では、バインド位置の値が最大 VARCHAR2 長を超えたことが原因として説明されています。つまり、単にLONG型の問題だけではなく、入力値の長さ、文字コード、列型、ドライバのバインド方法を合わせて確認する必要があります。
ORA-01461が出たら、まず対象列の型と長さ、投入値の
LENGTHB、アプリ側のバインド型を確認します。4000バイトを超える文字列を保存するなら、VARCHAR2 ではなく CLOB を検討します。一時的な回避で値を切り詰める場合も、業務上失ってよいデータか確認してください。ORA-01461とは
ORA-01461は、SQL構文ではなくバインド値と列定義の不一致で発生します。たとえば、画面の備考欄、JSON文字列、HTML本文、ログ文字列、Base64文字列などを通常の VARCHAR2 列へ保存しようとすると起きやすいです。
| 確認点 | よくある原因 | 修正の方向 |
|---|---|---|
| 列型 | VARCHAR2 列へ長文を保存している |
CLOB 列へ変更する |
| バイト数 | 文字数は少ないがUTF-8でバイト数が大きい | LENGTHB で確認する |
| アプリ側 | 長い文字列を通常のStringバインドで渡している | CLOBとしてバインドする |
| ORM | MyBatis/Hibernateの型指定が合っていない | jdbcTypeや@Lobを明示する |
| 設計 | 本来保存すべきでない巨大データを列へ入れている | 保存先や入力上限を見直す |
バインド変数の基本は Oracleバインド変数ガイド、バインド名や値の不足は ORA-01006、ORA-01008、ORA-01036 と合わせて切り分けます。
VARCHAR2・CLOB・LONGの違い
エラーメッセージに LONG と出ますが、新規設計でLONG型を選ぶ場面はほぼありません。長いテキストを保存するなら、通常は CLOB を使います。VARCHAR2 は短めの文字列、CLOB は長文、LONG は古い型として考えると整理しやすいです。
| 型 | 用途 | 注意点 |
|---|---|---|
VARCHAR2 |
名前、コード、短い説明など | SQL上の最大長やバイト数制限に注意 |
CLOB |
長文、本文、JSON、ログ、HTMLなど | DBMS_LOBやドライバのLOBバインドを使う |
LONG |
古い長文型 | 新規利用は避け、CLOBへの移行を検討する |
CLOB/BLOBの扱いは LOB完全ガイド と DBMS_LOB完全ガイド も参考になります。
4000バイト超の文字列をVARCHAR2列へ入れている
まずは対象列の定義と、投入しようとしている値の文字数・バイト数を確認します。日本語や絵文字を含む場合、文字数よりバイト数の方が大きくなります。
-- 列定義を確認
SELECT column_name,
data_type,
data_length,
char_length,
char_used
FROM user_tab_columns
WHERE table_name = 'ARTICLES'
AND column_name = 'BODY_TEXT';
-- 値の文字数とバイト数を確認
SELECT LENGTH(:body_text) AS char_len,
LENGTHB(:body_text) AS byte_len
FROM dual;
VARCHAR2(4000 BYTE) の列に、LENGTHB が4000を超える値を渡すと失敗します。保存すべき長文ならCLOB列へ変更し、保存不要なら入力上限や切り詰め仕様を決めます。数値精度の超過は ORA-01438 側の問題です。
BYTE/CHARとMAX_STRING_SIZEを確認する
VARCHAR2(4000 CHAR) と書いていても、どんな文字でも4000文字を必ず保存できる、という意味ではありません。Oracleの VARCHAR2 にはBYTE/CHARの長さ指定があり、さらにSQL上の最大サイズは MAX_STRING_SIZE の設定に左右されます。マルチバイト文字を扱うシステムでは、CHAR_USED、DATA_LENGTH、データベース文字セットを合わせて確認します。
-- 列のBYTE/CHAR指定と実際のバイト長を確認
SELECT column_name,
data_type,
data_length,
char_length,
char_used
FROM user_tab_columns
WHERE table_name = 'ARTICLES'
AND column_name IN ('TITLE', 'BODY_TEXT');
-- 文字セットと長さセマンティクスを確認
SELECT parameter, value
FROM nls_database_parameters
WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_LENGTH_SEMANTICS');
-- 権限があれば確認 SELECT name, value FROM v$parameter WHERE name = 'max_string_size';
MAX_STRING_SIZE=EXTENDED では VARCHAR2 の上限を拡張できますが、DB全体の設定変更や互換性確認が必要になるため、記事本文やJSONなど継続的に長くなる値の保存先としては、最初から CLOB を選ぶ方が安全なことが多いです。
CLOB列へ変更する
長文を業務上保存する必要があるなら、列を CLOB にします。既存列を直接変更できない場合は、新しいCLOB列を追加して移行する方法が安全です。
-- 新規列としてCLOBを追加する例 ALTER TABLE articles ADD (body_clob CLOB); -- 既存データを移行 UPDATE articles SET body_clob = TO_CLOB(body_text); -- アプリ側の参照先を切り替えた後、旧列を整理する
単純に列型を変えるだけでなく、アプリ側のバインド型、検索条件、インデックス、バックアップ、画面の入力制限も合わせて見直します。
JDBCでCLOBとしてバインドする
Javaアプリでは、長文を setString で渡しているとドライバや列定義によってORA-01461になることがあります。CLOB列へ保存する場合は、setClob や文字ストリームを使う設計にします。
String sql = "INSERT INTO articles (article_id, body_clob) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setLong(1, articleId);
ps.setCharacterStream(2, new StringReader(bodyText), bodyText.length());
ps.executeUpdate();
}
列が VARCHAR2 のままなら、アプリ側だけCLOBとして渡しても根本解決になりません。列定義とバインド方法をセットで合わせます。
MyBatisやHibernateで発生する場合
ORMやSQLマッパーでは、Java側の型やアノテーション、マッパーの jdbcType が列型と合っていないと、意図しないバインド型になってORA-01461が出ることがあります。
<insert id="insertArticle">
INSERT INTO articles (article_id, body_clob)
VALUES (#{articleId}, #{bodyText,jdbcType=CLOB})
</insert>
@Lob @Column(name = "BODY_CLOB") private String bodyText;
マッパー修正後も失敗する場合は、実際にDBへ送られているSQL、バインド値の長さ、列型をログで確認します。SQLに存在しないバインドを渡している場合は ORA-01006、バインド値不足なら ORA-01008 も疑います。
INSERTは通るのにUPDATEで失敗する場合
INSERT時とUPDATE時で使っているSQL、列、ドライバ設定、ORMのマッピングが違うと、片方だけORA-01461になることがあります。INSERTではCLOB列に入れているが、UPDATEでは別のVARCHAR2列へ入れている、というケースもあります。
-- INSERTとUPDATEで対象列が同じか確認する INSERT INTO articles (article_id, body_clob) VALUES (:article_id, :body_text); -- NG例: UPDATEでは短いVARCHAR2列へ入れている UPDATE articles SET body_text = :body_text WHERE article_id = :article_id;
SQLをログに出し、INSERTとUPDATEで対象列が同じか、バインド型が同じかを確認します。
LISTAGGや文字列連結で長くなっている場合
アプリから渡す値だけでなく、SQL内の文字列連結や LISTAGG で結果が長くなり、保存先の列に収まらないこともあります。LISTAGG の4000バイト制限や対処は LISTAGG関数ガイド も参考になります。
SELECT department_id,
LISTAGG(employee_name, ',') WITHIN GROUP (ORDER BY employee_name) AS names
FROM employees
GROUP BY department_id;
調査手順
ORA-01461は、列型、値の長さ、アプリ側のバインド型を順番に見ると切り分けやすいです。文字数ではなくバイト数で確認する点が大事です。
| 順番 | 確認すること | 見るポイント |
|---|---|---|
| 1 | 対象列の型と長さを確認する | USER_TAB_COLUMNS の DATA_TYPE と DATA_LENGTH |
| 2 | 投入値のバイト数を確認する | LENGTHB が列上限を超えていないか |
| 3 | SQLログを確認する | INSERT/UPDATEで対象列が違わないか |
| 4 | アプリ側のバインド型を確認する | String、CLOB、Stream、ORMの型指定 |
| 5 | 設計を決める | CLOB化、入力制限、切り詰め、保存先分離 |
チェックリスト
- 対象列が
VARCHAR2かCLOBか確認した LENGTHだけでなくLENGTHBでバイト数を確認したBYTE/CHAR指定とNLS_CHARACTERSETを確認したMAX_STRING_SIZEを確認し、拡張で解くべき問題かCLOB化すべき問題か判断した- 4000バイトを超える値を
VARCHAR2列へ入れていない - 長文保存が必要なら
CLOB列を使っている - JDBC/MyBatis/Hibernateのバインド型が列型と一致している
- INSERTとUPDATEで対象列やマッピングがずれていない
- 切り詰める場合は業務上データ欠落が許されるか確認した
よくある質問
ORA-01461はLONG型を使っていない場合でも出ますか?
出ます。メッセージにLONGとありますが、現在の実務ではVARCHAR2最大長を超える値や、CLOB相当の値を通常列へ渡した時にも見かけます。
文字数が4000未満なのに失敗するのはなぜですか?
Oracleの制限は文字数ではなくバイト数で効く場面があります。日本語や絵文字は1文字が複数バイトになるため、LENGTHB で確認してください。
とりあえずSUBSTRで切ってもよいですか?
ログやメモなど、欠落してもよいデータなら選択肢になります。ただし本文、契約文、JSONなど意味が壊れるデータではCLOB化を検討してください。
まとめ
ORA-01461は、長い文字列やLOB相当の値を、列型や最大長に合わない形でバインドした時に発生します。まず対象列の型、値の LENGTHB、アプリ側のバインド型を確認しましょう。
長文を保存する設計なら CLOB を使い、JDBCやORMでもCLOBとして扱います。短文列へ入れる設計なら、入力上限や切り詰め仕様を明確にして、4000バイト超の値が入らないようにします。
参考
ORA-01461 – Oracle Database Error Help
Introduction to Large Objects – Oracle Database SecureFiles and Large Objects Developer’s Guide

