CONVERT() 在 Oracle 中返回带有 CLOB 的垃圾

Mal*_*ous 3 oracle character-set utf-8

我希望修复 Oracle 中的数据表,理想情况下是通过非特权 SQL,该 SQL 已将 UTF-8 数据插入到 UTF-8 数据库中,错误地使用了 Latin-1 字符集。

该符号? GREEK SMALL LETTER BETA应该已进入数据库,但两个字符β已进入......因为两个 UTF-8 字符 Î LATIN CAPITAL LETTER I WITH CIRCUMFLEX后跟² SUPERSCRIPT TWO.

此示例代码演示了问题和修复方法,但它仅适用于VARCHAR列。一旦CLOB使用了a ,转换就会失败:

-- This must return AL32UTF8 for this example to be valid
SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER='NLS_CHARACTERSET';

CREATE TABLE EXAMPLE (T VARCHAR2(20));
INSERT INTO EXAMPLE (T) VALUES ('Example β');
SELECT T FROM EXAMPLE; -- Should return 'Example β'
SELECT CONVERT(T, 'WE8ISO8859P1') FROM EXAMPLE;
UPDATE EXAMPLE SET T=CONVERT(T, 'WE8ISO8859P1');
SELECT T FROM EXAMPLE; -- Should return 'Example ?', problem fixed
DROP TABLE EXAMPLE;
Run Code Online (Sandbox Code Playgroud)

但是,如果VARCHAR2(20)更改为,CLOB则不再有效。 CONVERT()返回垃圾字符。我可以TO_CHAR()用来解决这个问题,但最终我得到一个错误,该错误CLOB超过 4000 个字符,因此TO_CHAR()失败。

当使用CLOB超过 4000 个字符的列时,有没有办法让上面的例子工作?

Bal*_*app 5

DBMS_LOB包也有转换功能。不幸的是,不支持将 CLOB 转换为 CLOB 并一步更改字符集,因此首先将数据转换为 BLOB,然后再转换回 CLOB。

CREATE TABLE EXAMPLE (T CLOB);
INSERT INTO EXAMPLE (T) VALUES ('Example β ');

begin
  for i in 1..12
  loop
    update example set t = t || t;
  end loop;
  commit;
end;
/

select dbms_lob.getlength(t) from example;

DBMS_LOB.GETLENGTH(T)
---------------------
                45056
Run Code Online (Sandbox Code Playgroud)

现在转换部分:

create or replace function repair_data (p_clob clob) return clob as
  l_blob blob; 
  l_dest_offset number := 1;
  l_src_offset number := 1;
  l_lang_context number := 0;
  l_warning number;
  l_result clob;
begin
  dbms_lob.createtemporary(l_blob, true, dbms_lob.call);
  dbms_lob.createtemporary(l_result, true, dbms_lob.call);
  dbms_lob.converttoblob(l_blob, p_clob, dbms_lob.lobmaxsize, l_dest_offset, l_src_offset,
                         nls_charset_id('WE8ISO8859P1'), l_lang_context, l_warning);
  l_dest_offset := 1;
  l_src_offset := 1;
  l_lang_context := 0;
  dbms_lob.converttoclob(l_result, l_blob, dbms_lob.lobmaxsize, l_dest_offset, l_src_offset,
                         nls_charset_id('AL32UTF8'), l_lang_context, l_warning);
  return l_result;
end;
/

select repair_data(T) from example;

REPAIR_DATA(T)                          
----------------------------- 
Example ? Example ? Example ? ...

update example set t = repair_data(t);
...
Run Code Online (Sandbox Code Playgroud)