【Oracle】DBMS_LOB完全ガイド|CLOB・BLOB の読み書き・検索・一時LOB・VARCHAR2 との変換まで解説

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 で十分です。
スポンサーリンク

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 関数の 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 データ型完全ガイドを参照してください。