ORA-00932: inconsistent datatypes: expected %s got %s は、SQL の中で互換性のないデータ型を比較・結合・代入しようとしたときに発生するエラーです。たとえば VARCHAR2 の列と CLOB の列を = で比較したり、UNION の上下で列のデータ型が一致しない場合に発生します。
エラーメッセージの expected %s got %s の部分には「期待したデータ型」と「実際に渡されたデータ型」が表示されます。たとえば expected CHAR got CLOB なら、CHAR/VARCHAR2 を期待している箇所に CLOB が渡されたことが分かります。
- ORA-00932 が発生する主なパターン(7つ)と解決方法
- CLOB と VARCHAR2 の比較・結合で発生する場合の対処法
- DECODE / NVL / CASE で型不一致が起きる仕組みと回避方法
- UNION / UNION ALL で列の型が合わない場合の対処法
- DISTINCT / GROUP BY / ORDER BY で CLOB を使う方法
- 暗黙の型変換と明示的な型変換の使い分け
CLOB と VARCHAR2 の比較で発生する場合
最も多い ORA-00932 の原因が CLOB 列と VARCHAR2 の比較です。CLOB はラージオブジェクトのため、= 演算子や IN で直接比較できません。
-- CLOB 列を = で比較 → ORA-00932: inconsistent datatypes: expected CHAR got CLOB
SELECT * FROM documents
WHERE content = 'テスト'; -- content が CLOB 型の場合にエラー
-- CLOB 列を IN で比較 → 同じエラー
SELECT * FROM documents
WHERE content IN ('テスト', '本番');
-- ① DBMS_LOB.SUBSTR で先頭 N 文字を VARCHAR2 に変換して比較する
SELECT * FROM documents
WHERE DBMS_LOB.SUBSTR(content, 4000, 1) = 'テスト';
-- DBMS_LOB.SUBSTR(lob, 取得文字数, 開始位置)
-- 4000 バイト以内であれば VARCHAR2 として比較できる
-- ② TO_CHAR で変換する(4000 バイト以内の CLOB に使える)
SELECT * FROM documents
WHERE TO_CHAR(content) = 'テスト';
-- ③ LIKE で部分一致検索する(CLOB でも LIKE は使える)
SELECT * FROM documents
WHERE content LIKE '%テスト%';
-- ④ DBMS_LOB.INSTR で文字列の位置を検索する
SELECT * FROM documents
WHERE DBMS_LOB.INSTR(content, 'テスト') > 0;
-- ⑤ DBMS_LOB.COMPARE で比較する(完全一致)
SELECT * FROM documents d1
WHERE DBMS_LOB.COMPARE(d1.content, TO_CLOB('テスト')) = 0;
-- COMPARE の戻り値: 0=一致, -1=第1引数が小さい, 1=第1引数が大きい
DECODE / NVL / CASE で型不一致が起きる場合
DECODE や NVL は最初の引数(または戻り値)のデータ型を基準にして後続の値を暗黙変換しようとします。型が異なると ORA-00932 が発生します。
-- DECODE の第3引数(最初の戻り値)が基準型になる -- 第3引数が VARCHAR2 なら、以降の戻り値もすべて VARCHAR2 に変換される SELECT DECODE(status, 1, '有効', 2, '無効', NULL) FROM settings; -- ↑ これは OK(すべて VARCHAR2) -- 第3引数が NUMBER で第5引数が VARCHAR2 → ORA-00932 SELECT DECODE(status, 1, 100, 2, 'なし', NULL) FROM settings; -- expected NUMBER got CHAR(第3引数の 100 が NUMBER なので 'なし' を NUMBER に変換しようとする)
-- ① すべての戻り値を VARCHAR2 に統一する SELECT DECODE(status, 1, '100', 2, 'なし', NULL) FROM settings; -- 100 を文字列 '100' にすれば全引数が VARCHAR2 で統一される -- ② TO_CHAR で明示的に変換する SELECT DECODE(status, 1, TO_CHAR(100), 2, 'なし', NULL) FROM settings; -- ③ NVL の型不一致(第1引数と第2引数の型が異なる場合) -- NG: salary は NUMBER だが 'なし' は VARCHAR2 -- SELECT NVL(salary, 'なし') FROM employees; -- ORA-00932 -- OK: 両方を VARCHAR2 に統一する SELECT NVL(TO_CHAR(salary), 'なし') FROM employees; -- ④ CASE 式でも同じルールが適用される -- NG: -- SELECT CASE status WHEN 1 THEN 100 WHEN 2 THEN 'なし' END FROM settings; -- OK: 型を統一する SELECT CASE status WHEN 1 THEN '100' WHEN 2 THEN 'なし' END FROM settings;
UNION / UNION ALL で列の型が不一致の場合
UNION / UNION ALL は上下の SELECT の列数と型が一致している必要があります。型が異なると ORA-00932 が発生します。
-- 上の SELECT の第2列が NUMBER、下の SELECT の第2列が VARCHAR2 → エラー SELECT employee_id, salary FROM employees -- salary: NUMBER UNION ALL SELECT department_id, department_name FROM departments; -- department_name: VARCHAR2 -- ORA-00932: inconsistent datatypes: expected NUMBER got CHAR -- CLOB と VARCHAR2 の UNION もエラー SELECT doc_id, content FROM documents -- content: CLOB UNION ALL SELECT log_id, message FROM audit_logs; -- message: VARCHAR2 -- ORA-00932: inconsistent datatypes: expected CLOB got CHAR
-- ① TO_CHAR で NUMBER を VARCHAR2 に変換する SELECT employee_id, TO_CHAR(salary) AS col2 FROM employees UNION ALL SELECT department_id, department_name FROM departments; -- ② CLOB と VARCHAR2 を統一する(TO_CLOB で VARCHAR2 を CLOB に変換) SELECT doc_id, content FROM documents UNION ALL SELECT log_id, TO_CLOB(message) FROM audit_logs; -- ③ CAST で型を明示的に合わせる SELECT employee_id, CAST(salary AS VARCHAR2(100)) AS col2 FROM employees UNION ALL SELECT department_id, department_name FROM departments; -- ④ NULL 列の型を明示する(NULL はデフォルトで CHAR 型と解釈される) SELECT employee_id, salary FROM employees UNION ALL SELECT department_id, CAST(NULL AS NUMBER) FROM departments; -- NULL を NUMBER 列の位置に置く場合は CAST(NULL AS NUMBER) で型を明示する
DISTINCT / GROUP BY / ORDER BY で CLOB を使う場合
CLOB 列は DISTINCT・GROUP BY・ORDER BY に直接使えません。これらの操作は値の比較が必要ですが、CLOB は比較演算子を直接サポートしないためです。
-- ORA-00932: inconsistent datatypes: expected - got CLOB SELECT DISTINCT content FROM documents; -- ORA-00932 SELECT content, COUNT(*) FROM documents GROUP BY content; -- ORA-00932(ORDER BY でも) SELECT doc_id, content FROM documents ORDER BY content;
-- ① DBMS_LOB.SUBSTR で先頭 N 文字に切り詰めて DISTINCT する
SELECT DISTINCT DBMS_LOB.SUBSTR(content, 4000, 1) AS content_short
FROM documents;
-- ② DBMS_LOB.GETLENGTH でソートする(内容ではなく長さでソート)
SELECT doc_id, content
FROM documents
ORDER BY DBMS_LOB.GETLENGTH(content) DESC;
-- ③ ORA_HASH で CLOB のハッシュ値を使って GROUP BY する(重複判定)
SELECT ORA_HASH(content) AS content_hash, COUNT(*)
FROM documents
GROUP BY ORA_HASH(content);
-- ④ CLOB を含むテーブルで重複行を検出する
SELECT doc_id, doc_name
FROM documents d1
WHERE EXISTS (
SELECT 1 FROM documents d2
WHERE d1.doc_id != d2.doc_id
AND DBMS_LOB.COMPARE(d1.content, d2.content) = 0
);
INSERT / UPDATE で型不一致が起きる場合
-- NG: VARCHAR2 列に CLOB を直接 INSERT する(4000 バイト超の場合)
-- INSERT INTO log_table (message) SELECT content FROM documents;
-- → content が 4000 バイト超の CLOB なら ORA-00932
-- OK: DBMS_LOB.SUBSTR で切り詰める
INSERT INTO log_table (message)
SELECT DBMS_LOB.SUBSTR(content, 4000, 1) FROM documents;
-- OK: ターゲット列を CLOB に変更する
ALTER TABLE log_table MODIFY message CLOB;
INSERT INTO log_table (message) SELECT content FROM documents;
-- NG: DATE 列に文字列を直接 INSERT する(NLS_DATE_FORMAT に依存して失敗する場合)
-- INSERT INTO events (event_date) VALUES ('2026-04-10');
-- → NLS_DATE_FORMAT が 'DD-MON-RR' の場合は ORA-01843 や ORA-00932
-- OK: TO_DATE で明示的に変換する
INSERT INTO events (event_date) VALUES (TO_DATE('2026-04-10', 'YYYY-MM-DD'));
バインド変数の型不一致で発生する場合
-- PL/SQL でのバインド変数型不一致
-- NG: NUMBER 型の変数を CLOB 列と比較
DECLARE
v_id NUMBER := 100;
BEGIN
-- CLOB 型の列に NUMBER を比較 → ORA-00932
-- SELECT ... WHERE clob_column = v_id;
NULL;
END;
/
-- JDBC / Python などアプリケーション側でのバインド変数型指定
-- Java:
-- PreparedStatement ps = conn.prepareStatement("SELECT * FROM t WHERE clob_col = ?");
-- ps.setString(1, "test"); -- CLOB 列に setString → ORA-00932 の場合がある
--
-- 解決策: SQL 側で DBMS_LOB.SUBSTR で VARCHAR2 に変換するか、
-- ps.setCharacterStream() を使う
-- Python (python-oracledb):
-- cursor.execute("SELECT * FROM t WHERE clob_col = :val", val="test")
-- → ORA-00932 になる場合がある
--
-- 解決策:
-- cursor.execute(
-- "SELECT * FROM t WHERE DBMS_LOB.SUBSTR(clob_col,4000,1) = :val",
-- val="test"
-- )
-- または TO_CLOB(:val) でバインド変数側を CLOB にする
暗黙の型変換が効くケースと効かないケース
Oracle は一部の型の組み合わせで暗黙変換(自動的な型変換)を行います。暗黙変換が効く場合はエラーにならないため、「なぜこの SQL はエラーにならないのに別の SQL ではエラーになるのか」という混乱が起きることがあります。
| 比較 | 暗黙変換 | 結果 |
|---|---|---|
| VARCHAR2 = NUMBER | VARCHAR2 → NUMBER に変換 | 暗黙変換が効く(ただし変換不能な値は ORA-01722) |
| VARCHAR2 = DATE | VARCHAR2 → DATE に変換(NLS_DATE_FORMAT 依存) | 暗黙変換が効くが環境依存で危険 |
| NUMBER = DATE | 変換不可 | ORA-00932 |
| VARCHAR2 = CLOB | 変換不可(= 演算子では) | ORA-00932 |
| CLOB = CLOB | 変換不可(= 演算子では) | ORA-00932(DBMS_LOB.COMPARE を使う) |
| VARCHAR2 || CLOB | VARCHAR2 → CLOB に変換 | 暗黙変換が効く(結果は CLOB) |
| BLOB = VARCHAR2 | 変換不可 | ORA-00932 |
暗黙変換は NLS 設定や Oracle バージョンによって挙動が変わる場合があります。本番コードでは必ず TO_CHAR / TO_NUMBER / TO_DATE / CAST で明示的に型変換するべきです。暗黙変換に頼ると、開発環境では動くが本番環境ではエラーになるという事態が起きます。
まとめ
- CLOB と VARCHAR2 の比較:
=は使えない。DBMS_LOB.SUBSTR(clob, 4000, 1)で VARCHAR2 に変換するか、LIKE/DBMS_LOB.INSTRで検索する - DECODE / NVL / CASE:最初の戻り値の型が基準になる。すべての戻り値の型を統一するか、
TO_CHARで明示的に変換する - UNION / UNION ALL:上下の SELECT の対応する列の型を一致させる。
TO_CHAR・TO_CLOB・CASTで統一する。NULL はCAST(NULL AS 型)で型を明示する - DISTINCT / GROUP BY と CLOB:CLOB は直接使えない。
DBMS_LOB.SUBSTRで切り詰めるか、ORA_HASHでハッシュ化する - 暗黙変換:VARCHAR2 ↔ NUMBER・VARCHAR2 ↔ DATE は暗黙変換が効くが、環境依存で危険。本番コードでは明示的に型変換すること
データ型の詳細については Oracle データ型完全ガイドを参照してください。CLOB / BLOB の操作全般については Oracle LOB 完全ガイドも参照してください。