2013-08-29 4 views
3

Я работаю с базой данных Oracle и хочу определить длину в байтах NCLOB с использованием многобайтовой кодировки (UTF-8).Определить длину в байтах CLOB/NCLOB с многобайтовой кодировкой

LENGTHB() не поддерживает CLOB или NCLOBS с многобайтовой кодировкой. I может преобразовать NCLOB в BLOB и затем получить его длину. Но разве нет лучшего способа сделать это?

ответ

3

Oracle хранит CLOB в UTF-16 (или, возможно, ваш NCHARACTER_SET?). Каждый символ хранится как два байта.

Вот как вы можете увидеть исходные данные:

SQL> CREATE TABLE test_clob (c CLOB, v VARCHAR2(10 CHAR), nv NVARCHAR2(10)); 

Table created 

SQL> INSERT INTO test_clob VALUES ('', '', ''); 

1 row inserted 

SQL> SELECT dbms_rowid.rowid_relative_fno(ROWID), 
    2   dbms_rowid.rowid_block_number(ROWID) 
    3 FROM test_clob; 

DBMS_ROWID.ROWID_RELATIVE_FNO(DBMS_ROWID.ROWID_BLOCK_NUMBER(
------------------------------ ------------------------------ 
          13       94314 

SQL> alter system dump datafile 13 block 94314; 

System altered 

Перейдите в свой USER_DUMP_DEST каталог и откройте файл трассировки, вы должны увидеть что-то вроде этого:

col 0: [56] 
00 54 00 01 02 0c 80 00 00 02 00 00 00 01 00 00 03 64 c6 a5 00 24 09 00 00 
00 00 00 00 14 00 00 00 00 00 01 00 30 00 31 00 32 00 33 00 34 00 35 00 36 
00 37 00 38 00 39 
LOB 
Locator: 
    Length:  84(56) 
    Version:  1 
    Byte Length: 2 
    LobID: 00.00.00.01.00.00.03.64.c6.a5 
    Flags[ 0x02 0x0c 0x80 0x00 ]: 
    Type: CLOB 
    [...] 
    Inline data[20] 
    [...] 
col 1: [10] 30 31 32 33 34 35 36 37 38 39 
col 2: [20] 00 30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 

Как вы можете видеть CLOB (столбец 0) состоит из нескольких байтов заголовка и тех же исходных данных байта, что и столбец UTF-16 NVARCHAR2.

Как таковой, я думаю, вам нужно будет преобразовать CLOB в UTF-8, чтобы определить его длину в этом наборе символов.

Вот пример я использовал с помощью DBMS_LOB.converttoblob:

SQL> DECLARE 
    2  l_clob   CLOB := 'abcdéfghij'; -- the é will take two bytes! 
    3  l_blob   BLOB; 
    4  l_dest_offset NUMBER := 1; 
    5  l_src_offset NUMBER := 1; 
    6  l_lang_context NUMBER := 0; 
    7  l_warning  NUMBER; 
    8 BEGIN 
    9  dbms_lob.createtemporary(l_blob, FALSE, dbms_lob.call); 
10  dbms_lob.converttoblob(dest_lob  => l_blob, 
11       src_clob  => l_clob, 
12       amount  => dbms_lob.lobmaxsize, 
13       dest_offset => l_dest_offset, 
14       src_offset => l_src_offset, 
15       blob_csid => nls_charset_id('AL32UTF8'), 
16       lang_context => l_lang_context, 
17       warning  => l_warning); 
18  dbms_output.put_line('byte length:'||dbms_lob.getlength(l_blob)); 
19  dbms_lob.freetemporary(l_blob); 
20 END; 
21/

byte length:11 

PL/SQL procedure successfully completed 

Вы можете конвертировать в любой набор символов с помощью функции nls_charset_id.

+0

То, что я на самом деле делаю, прежде чем хочу, чтобы длина моего UTF-8 NCLOB. У меня CLOB в кодировке Windows-1252, и я попытался вызвать 'CONVERT (my_clob, 'UTF8', 'WE8MSWIN1252')', чтобы преобразовать его в NCLOB в UTF-8. Но получается, что 'CONVERT (CLOB, VARCHAR2, VARCHAR2)' возвращает некоторый псевдо UTF-8 CLOB (а не NCLOB) с некоторым нечетным заполнением, которое может быть UTF-16 ... – Dave

+0

@dave Я не думаю ' convert' будет делать то, что вы думаете, что он делает. ['CONVERT'] (http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions034.htm#i77037) вернет CLOB, который имеет тот же самый исходный набор символов, что и первый, хотя данные будут разными. Я добавил пример с 'dbms_lob.converttoblob', который должен работать со всеми клобами. –

+0

Винсент, не уверен, почему, но я получаю длину байта: 15 для этого примера, где, если я сброшу эту строку, я получу ожидаемую длину 11. Не уверен, почему это расхождение. – tbone

Смежные вопросы