【Oracle】ORA-01461の原因と解決方法|can bind a LONG value only for insert into a LONG column

【Oracle】ORA-01461の原因と解決方法|can bind a LONG value only for insert into a LONG column Oracle

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-01006ORA-01008ORA-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列へ入れている

まずは対象列の定義と、投入しようとしている値の文字数・バイト数を確認します。日本語や絵文字を含む場合、文字数よりバイト数の方が大きくなります。

check-column-length-and-value-bytes.sql
-- 列定義を確認
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_USEDDATA_LENGTH、データベース文字セットを合わせて確認します。

check-varchar2-semantics.sql
-- 列の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');
check-max-string-size.sql
-- 権限があれば確認
SELECT name, value
FROM v$parameter
WHERE name = 'max_string_size';

MAX_STRING_SIZE=EXTENDED では VARCHAR2 の上限を拡張できますが、DB全体の設定変更や互換性確認が必要になるため、記事本文やJSONなど継続的に長くなる値の保存先としては、最初から CLOB を選ぶ方が安全なことが多いです。

CLOB列へ変更する

長文を業務上保存する必要があるなら、列を CLOB にします。既存列を直接変更できない場合は、新しいCLOB列を追加して移行する方法が安全です。

alter-varchar2-to-clob.sql
-- 新規列として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 や文字ストリームを使う設計にします。

jdbc-clob-bind.java
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が出ることがあります。

mybatis-clob-jdbctype.xml
<insert id="insertArticle">
  INSERT INTO articles (article_id, body_clob)
  VALUES (#{articleId}, #{bodyText,jdbcType=CLOB})
</insert>
hibernate-lob-annotation.java
@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列へ入れている、というケースもあります。

compare-insert-update-target-columns.sql
-- 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関数ガイド も参考になります。

listagg-result-too-long.sql
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_COLUMNSDATA_TYPEDATA_LENGTH
2 投入値のバイト数を確認する LENGTHB が列上限を超えていないか
3 SQLログを確認する INSERT/UPDATEで対象列が違わないか
4 アプリ側のバインド型を確認する String、CLOB、Stream、ORMの型指定
5 設計を決める CLOB化、入力制限、切り詰め、保存先分離

チェックリスト

  • 対象列が VARCHAR2CLOB か確認した
  • 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

Data Types – Oracle Database SQL Language Reference

NLS_LENGTH_SEMANTICS – Oracle Database Reference