web-dev-qa-db-ja.com

OracleでCLOB列のサイズをバイト単位で取得する方法は?

OracleのCLOB列のサイズをバイト単位で取得するにはどうすればよいですか?

LENGTH()DBMS_LOB.getLength()は両方ともCLOBで使用される文字数を返しますが、使用されているバイト数を知る必要があります(マルチバイト文字セットを扱っています)。

32
rag

いくつかの考えの後、私はこの解決策を思いついた:

 LENGTHB(TO_CHAR(SUBSTR(<CLOB-Column>,1,4000)))

SUBSTRは、最初の4000文字(最大文字列サイズ)のみを返します

TO_CHARCLOBからVARCHAR2に変換します

LENGTHBは、文字列が使用するバイト単位の長さを返します。

17
rag

コメントを回答として追加します。これは、受け入れられた回答よりも幅広いケースで元の問題を解決するためです。注:データに含まれるマルチバイト文字の最大長とおおよその割合を把握する必要があります。

4000バイトを超えるCLOBがある場合、SUBSTRではなくDBMS_LOB.SUBSTRを使用する必要があります。 amountおよびoffsetパラメーターは、 DBMS_LOB.SUBSTR。

次に、このパラメーターはcharactersの数であり、マルチバイト文字がある場合は4000であるため、4000未満のサブストリングが必要になる場合があります文字は4000bytesを超える長さになり、ORA-06502: PL/SQL: numeric or value error: character string buffer too smallは、サブストリングの結果が4000バイト制限のVARCHAR2に収まる必要があるためです。正確に取得できる文字数は、データ内の文字ごとの平均バイト数によって異なります。

だから私の答えは:

LENGTHB(TO_CHAR(DBMS_LOB.SUBSTR(<CLOB-Column>,3000,1)))
+NVL(LENGTHB(TO_CHAR(DBM‌​S_LOB.SUBSTR(<CLOB-Column>,3000,3001))),0)
+NVL(LENGTHB(TO_CHAR(DBM‌​S_LOB.SUBSTR(<CLOB-Column>,6000,6001))),0)
+...

最長のCLOBをカバーするために必要な数のチャンクを追加し、データの文字あたりの平均バイト数に従ってチャンクサイズを調整します。

16
Andrew Spencer

VARCHAR2より大きいCLOBサイズの場合は、これを試してください。

CLOBを「VARCHAR2互換」サイズの部分に分割し、CLOBデータのすべての部分でlengthbを実行し、すべての結果を要約する必要があります。

declare
   my_sum int;
begin
   for x in ( select COLUMN, ceil(DBMS_LOB.getlength(COLUMN) / 2000) steps from TABLE ) 
   loop
       my_sum := 0;
       for y in 1 .. x.steps
       loop
          my_sum := my_sum + lengthb(dbms_lob.substr( x.COLUMN, 2000, (y-1)*2000+1 ));
          -- some additional output
          dbms_output.put_line('step:' || y );
          dbms_output.put_line('char length:' || DBMS_LOB.getlength(dbms_lob.substr( x.COLUMN, 2000 , (y-1)*2000+1 )));
          dbms_output.put_line('byte length:' || lengthb(dbms_lob.substr( x.COLUMN, 2000, (y-1)*2000+1 )));
          continue;
        end loop;
        dbms_output.put_line('char summary:' || DBMS_LOB.getlength(x.COLUMN));
        dbms_output.put_line('byte summary:' || my_sum);
        continue;
    end loop;
end;
/
6
TobiK

NVL(length(clob_col_name)、0)は私のために機能します。

5
user5534142

簡単な解決策は、CLOBをBLOBにキャストしてから、BLOBの長さを要求することです!

問題は、OracleにはCLOBをBLOBにキャストする関数がありませんが、それを行う関数を簡単に定義できることです。

create or replace
FUNCTION clob2blob (p_in clob) RETURN blob IS 
    v_blob        blob;
    v_desc_offset PLS_INTEGER := 1;
    v_src_offset  PLS_INTEGER := 1;
    v_lang        PLS_INTEGER := 0;
    v_warning     PLS_INTEGER := 0;  
BEGIN
    dbms_lob.createtemporary(v_blob,TRUE);
    dbms_lob.converttoblob
        ( v_blob
        , p_in
        , dbms_lob.getlength(p_in)
        , v_desc_offset
        , v_src_offset
        , dbms_lob.default_csid
        , v_lang
        , v_warning
        );
    RETURN v_blob;
END;

バイト数を取得するために使用するSQLコマンドは

SELECT length(clob2blob(fieldname)) as nr_bytes 

または

SELECT dbms_lob.getlength(clob2blob(fieldname)) as nr_bytes

Unicode(UTF-8)を使用せずにOracle 10gでこれをテストしました。しかし、Unicode(UTF-8)Oracleインスタンスを使用すると、このソリューションは正しいに違いないと思います:-)

Clobをblobに変換するソリューションを投稿したNashevに感謝します OracleでCLOBをBLOBに変換する方法 と、ドイツ語で書かれたこの投稿(コードはPL/SQLにあります) 13ter.info.blog それはさらにblobをclobに変換する関数を与えます!

誰かがUnicode(UTF-8)CLOBで2つのコマンドをテストできるので、これはUnicodeで動作することを確信していますか?

4
schlebe

テーブル名を使用して、dba_lobsからLOBセグメント名を確認します。

select TABLE_NAME,OWNER,COLUMN_NAME,SEGMENT_NAME from dba_lobs where TABLE_NAME='<<TABLE NAME>>';

次に、セグメント名を使用して、dba_segmentsで使用されているバイトを見つけます。

select s.segment_name, s.partition_name, bytes/1048576 "Size (MB)"
from dba_segments s, dba_lobs l
where s.segment_name = l.segment_name
and s.owner = '<< OWNER >> ' order by s.segment_name, s.partition_name;
3
Nalla Krishna