Oracle の LOB(Large Object)データ型は、テキスト(CLOB)・バイナリ(BLOB)・ファイル参照(BFILE)など大容量データを格納するために使います。VARCHAR2 の 32,767 バイト制限を超えるデータを扱う場合に必要です。
LOB データの操作には DBMS_LOB パッケージを使います。SQL 関数(SUBSTR・INSTR)は LOB に対して使えないものや制限があるため、DBMS_LOB が提供する専用の関数・プロシージャを使う必要があります。
この記事でわかること
- CLOB・BLOB の基本操作(GETLENGTH・SUBSTR・INSTR)
- DBMS_LOB.READ / WRITE / APPEND / COPY の使い方
- EMPTY_CLOB() / EMPTY_BLOB() で LOB 列を初期化する方法
- 一時 LOB(CREATETEMPORARY / FREETEMPORARY)で PL/SQL 内での作業領域を確保する
- VARCHAR2 と CLOB の変換・大きな CLOB を分割して処理するパターン
- CLOB の内容を検索・置換するパターン
CLOB と VARCHAR2/NVARCHAR2 の使い分け
VARCHAR2 / NVARCHAR2 は最大 32,767 バイト(PL/SQL 内)、SQL では 4,000 バイトが上限です。これを超えるデータには CLOB を使います。ただし CLOB は格納・操作コストが高いため、4,000 バイト以下であれば VARCHAR2 で十分です。
VARCHAR2 / NVARCHAR2 は最大 32,767 バイト(PL/SQL 内)、SQL では 4,000 バイトが上限です。これを超えるデータには CLOB を使います。ただし CLOB は格納・操作コストが高いため、4,000 バイト以下であれば VARCHAR2 で十分です。
DBMS_LOB の基本操作(読み込み・長さ取得・検索)
GETLENGTH・SUBSTR・INSTR — CLOB の長さ取得・部分取得・検索
DECLARE
v_clob CLOB;
v_len NUMBER;
v_part VARCHAR2(200);
v_pos NUMBER;
BEGIN
-- CLOB 列を取得
SELECT content_clob INTO v_clob FROM documents WHERE doc_id = 1;
-- 長さを取得(文字数)
v_len := DBMS_LOB.GETLENGTH(v_clob);
DBMS_OUTPUT.PUT_LINE('長さ: ' || v_len || ' 文字');
-- 先頭 100 文字を取得(SUBSTR: 開始位置は1始まり)
v_part := DBMS_LOB.SUBSTR(v_clob, 100, 1); -- (LOB, 長さ, 開始位置)
DBMS_OUTPUT.PUT_LINE('先頭100文字: ' || v_part);
-- キーワードの位置を検索(INSTR)
v_pos := DBMS_LOB.INSTR(v_clob, 'エラー', 1, 1); -- (LOB, パターン, 開始位置, 出現回数)
IF v_pos > 0 THEN
DBMS_OUTPUT.PUT_LINE('"エラー" は ' || v_pos || ' 文字目にあります');
END IF;
END;
/
DBMS_LOB.SUBSTR と SQL の SUBSTR の違い
SQL 関数の
SQL 関数の
SUBSTR(clob_col, 1, 100) は CLOB に対して使えますが、返す値は VARCHAR2(最大 32,767 文字)に変換されます。CLOB 全体を操作する場合は DBMS_LOB.READ を使います。
DBMS_LOB.READ — 大きな CLOB を分割して読み込む
DECLARE
v_clob CLOB;
v_buf VARCHAR2(32767);
v_offset NUMBER := 1;
v_amount NUMBER := 32767; -- 一度に読む最大文字数
v_total NUMBER;
BEGIN
SELECT content_clob INTO v_clob FROM documents WHERE doc_id = 1;
v_total := DBMS_LOB.GETLENGTH(v_clob);
-- 32767 文字ずつ分割して処理
WHILE v_offset <= v_total LOOP
DBMS_LOB.READ(
lob_loc => v_clob, -- LOB ロケーター
amount => v_amount, -- 読み込む文字数(IN/OUT: 実際に読んだ数が返る)
offset => v_offset, -- 読み込み開始位置(1始まり)
buffer => v_buf -- 結果を受け取るバッファ
);
-- v_buf を使った処理(例: 検索・解析など)
DBMS_OUTPUT.PUT_LINE('読み込み: ' || LENGTH(v_buf) || ' 文字');
v_offset := v_offset + v_amount;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL; -- READ は読み切ると NO_DATA_FOUND を発生させる(通常は GETLENGTH で制御)
END;
/
LOB への書き込み(WRITE・APPEND・COPY)
EMPTY_CLOB() で初期化して WRITE で書き込む
-- CLOB 列を持つテーブルの例
-- CREATE TABLE documents (doc_id NUMBER, content_clob CLOB);
DECLARE
v_clob CLOB;
v_data VARCHAR2(1000) := '最初のテキストデータです。';
BEGIN
-- NULL と EMPTY_CLOB() の違い:
-- NULL: LOB ロケーター自体が存在しない(DBMS_LOB で操作不可)
-- EMPTY_CLOB(): ロケーターは存在するが長さ0の LOB
-- RETURNING INTO で LOB ロケーターを取得してから書き込む
INSERT INTO documents (doc_id, content_clob)
VALUES (1, EMPTY_CLOB())
RETURNING content_clob INTO v_clob;
-- WRITE で書き込む(offset=1, amount=文字列の長さ)
DBMS_LOB.WRITE(v_clob, LENGTH(v_data), 1, v_data);
COMMIT;
DBMS_OUTPUT.PUT_LINE('書き込み完了: ' || DBMS_LOB.GETLENGTH(v_clob) || ' 文字');
END;
/
APPEND で LOB に追記する
DECLARE
v_clob CLOB;
v_add_data VARCHAR2(200) := ' 追加テキストです。';
BEGIN
-- 更新対象の LOB ロケーターを FOR UPDATE で取得
SELECT content_clob INTO v_clob
FROM documents
WHERE doc_id = 1
FOR UPDATE;
-- APPEND: 末尾に追加(バッファ文字列を直接 CLOB に追加)
DBMS_LOB.WRITEAPPEND(v_clob, LENGTH(v_add_data), v_add_data);
COMMIT;
DBMS_OUTPUT.PUT_LINE('追記後の長さ: ' || DBMS_LOB.GETLENGTH(v_clob) || ' 文字');
END;
/
一時 LOB — PL/SQL 内での作業領域として使う
DB テーブルに保存しない一時的な LOB データは一時 LOBとして扱います。TEMP 表領域に作成され、セッション終了時または明示的に FREETEMPORARY を呼んだときに解放されます。
CREATETEMPORARY と FREETEMPORARY — 一時 CLOB の使い方
DECLARE
v_temp_clob CLOB;
v_data VARCHAR2(1000);
BEGIN
-- 一時 CLOB を作成(TEMP 表領域に確保)
DBMS_LOB.CREATETEMPORARY(
lob_loc => v_temp_clob,
cache => TRUE, -- バッファキャッシュを使用するか
dur => DBMS_LOB.SESSION -- SESSION: セッション終了まで / CALL: 呼び出し終了まで
);
-- 一時 CLOB にデータを書き込む
DBMS_LOB.WRITEAPPEND(v_temp_clob, LENGTH('最初の行' || CHR(10)), '最初の行' || CHR(10));
DBMS_LOB.WRITEAPPEND(v_temp_clob, LENGTH('2番目の行' || CHR(10)), '2番目の行' || CHR(10));
-- CLOB の一部を VARCHAR2 に取り出して処理
v_data := DBMS_LOB.SUBSTR(v_temp_clob, 100, 1);
DBMS_OUTPUT.PUT_LINE('内容: ' || v_data);
-- 処理完了後に明示的に解放(メモリリーク防止)
DBMS_LOB.FREETEMPORARY(v_temp_clob);
EXCEPTION
WHEN OTHERS THEN
IF DBMS_LOB.ISTEMPORARY(v_temp_clob) = 1 THEN
DBMS_LOB.FREETEMPORARY(v_temp_clob);
END IF;
RAISE;
END;
/
VARCHAR2 と CLOB の相互変換
VARCHAR2 を CLOB に変換・CLOB を VARCHAR2 に変換する
DECLARE
v_varchar VARCHAR2(4000) := '短いテキスト(4000文字以内)';
v_clob CLOB;
v_result VARCHAR2(32767);
BEGIN
-- VARCHAR2 → CLOB(暗黙変換可能。または TO_CLOB() 関数)
v_clob := TO_CLOB(v_varchar);
DBMS_OUTPUT.PUT_LINE('CLOB 長さ: ' || DBMS_LOB.GETLENGTH(v_clob));
-- CLOB → VARCHAR2(32767 文字以内の場合のみ直接変換可能)
SELECT content_clob INTO v_clob FROM documents WHERE doc_id = 1;
IF DBMS_LOB.GETLENGTH(v_clob) <= 32767 THEN
v_result := v_clob; -- 暗黙変換(32767文字以内の場合)
DBMS_OUTPUT.PUT_LINE('変換OK: ' || LENGTH(v_result) || ' 文字');
ELSE
-- 32767文字を超える場合は DBMS_LOB.SUBSTR で分割して処理
v_result := DBMS_LOB.SUBSTR(v_clob, 32767, 1); -- 先頭 32767 文字のみ取得
DBMS_OUTPUT.PUT_LINE('先頭のみ: ' || LENGTH(v_result) || ' 文字');
END IF;
END;
/
CLOB 内の文字列検索と置換
SQL での CLOB 検索(INSTR / LIKE)
-- LIKE は CLOB に使えない(一部バージョンで非推奨) -- INSTR で代替する SELECT doc_id FROM documents WHERE DBMS_LOB.INSTR(content_clob, 'エラーコード', 1, 1) > 0; -- SQL の INSTR 関数も CLOB に使用可能(短い検索文字列のみ) SELECT doc_id FROM documents WHERE INSTR(content_clob, 'エラーコード') > 0;
CLOB 内の文字列を置換する(DBMS_LOB + 再構築)
-- CLOB 内の特定文字列を全置換する(REGEXP_REPLACE は CLOB に対応) UPDATE documents SET content_clob = REGEXP_REPLACE(TO_CLOB(content_clob), '旧文字列', '新文字列', 1, 0) WHERE doc_id = 1; -- ※ REGEXP_REPLACE は Oracle 11g 以降で CLOB に使用可能 -- ※ REPLACE 関数も CLOB に使用可能 COMMIT;
まとめ — DBMS_LOB の主要サブプログラム一覧
| サブプログラム | 用途 | 対象 LOB 型 |
|---|---|---|
GETLENGTH(lob) |
LOB の文字数(CLOB)またはバイト数(BLOB)を返す | CLOB・BLOB・BFILE |
SUBSTR(lob, n, pos) |
pos 文字目から n 文字分を VARCHAR2 / RAW で取得 | CLOB・BLOB・BFILE |
INSTR(lob, pattern, pos, n) |
n 番目のパターンが最初に出現する位置を返す | CLOB・BLOB・BFILE |
READ(lob, amount, offset, buffer) |
LOB を分割して buffer に読み込む | CLOB・BLOB・BFILE |
WRITE(lob, amount, offset, buffer) |
LOB の offset から buffer を書き込む(上書き) | CLOB・BLOB |
WRITEAPPEND(lob, amount, buffer) |
LOB の末尾に buffer を追記する | CLOB・BLOB |
APPEND(dest_lob, src_lob) |
src_lob の内容を dest_lob の末尾に追記する | CLOB・BLOB |
COPY(dest, src, n, doff, soff) |
src の soff から n 文字を dest の doff に上書きコピー | CLOB・BLOB |
ERASE(lob, amount, offset) |
LOB の offset から amount 文字分をスペース/ゼロで上書き | CLOB・BLOB |
TRIM(lob, newlen) |
LOB を newlen の長さに切り詰める | CLOB・BLOB |
CREATETEMPORARY(lob, cache, dur) |
一時 LOB をTEMP領域に作成する | CLOB・BLOB |
FREETEMPORARY(lob) |
一時 LOB を解放する | CLOB・BLOB |
ISTEMPORARY(lob) |
一時LOBかどうかを確認する(1=Yes, 0=No) | CLOB・BLOB |
LOB セグメントのサイズ管理・クリーンアップ方法はLOB セグメントの削除と表領域解放完全ガイドを参照してください。データ型の選び方全般は Oracle データ型完全ガイドを参照してください。