Oracle 字符集转换(10):6.3。如何将CLOB类型转换为韩文
我们来看看CLOB类型韩文转换方法。在US7ASCII字符集DB中,可以查看CLOB类型包括Hangul如何转换为AL32UTF8以及转换结果。
这是上一篇文章的延续。
Oracle字符集转换(九):6.如何转换用户实现的字符集(二)
6.3.如何将CLOB类型转换为韩文
Oracle字符集转换(八):六、如何转换用户实现的字符集(一)
在上面的文章中,我提到了以下内容:
作为参考,在US7ASCII到AL32UTF8转换的情况下,CLOB类型的列不能正常转换,所以需要单独处理。
将在下一篇文章中解释。
在本文中,我们将说明如何使用 DB Link 从 US7ASCII 到 AL32UTF8 将包括韩文字符的 CLOB 类型转换为 AL32UTF8。使用 DBMS_LOB,这是一个 Oracle 基本包。
首先,让我们检查来自三个实例的 CLOB 数据:ORAUS7、ORAMSWIN949 和 ORAUTF。
6.3.1.检查 CLOB 数据
通过在三个实例上执行下面的 INSERT 语句,用数据填充 CLOB 列 (REF_DES):ORAUS7、ORAMSWIN949 和 ORAUTF。
INSERT INTO SUB_MON_STAT (USE_MON, LINE_NUM, SUB_STA_ID, SUB_STA_NM, RIDE_PASGR_NUM, ALIGHT_PASGR_NUM, WORK_DT, COMMT, REF_DES, REF_IMG) VALUES ('201301', '1호선', '0150', '서울역', 2199181, 1855268, '20130723', RPAD('서울역', 3000, '서울역'), RPAD('서울역', 3000, '서울역'), UTL_RAW.CAST_TO_RAW('12345')) ;
每列的数据类型如下。
现在,让我们使用以下 SQL 检查每个实例中的 ref_des 列(CLOB 类型)数据。
select dbms_lob.getlength(ref_des) chr_len ,lengthb(dbms_lob.substr(ref_des, dbms_lob.getlength(ref_des), 1)) byte_len ,dump(dbms_lob.substr(ref_des, dbms_lob.getlength(ref_des), 1), 1016) dp ,ref_des from sub_mon_stat where ref_des is not null and rownum <= 1 ;
▼ 奥拉斯7
CLOB数据的字符集是US7ASCII,韩文字符显示不正常。
字符数(chr_len)是3000,字节数(byte_len)也是3000。即可以看出一个字符存储为一个字节。
我找不到在 SQL Developer 中设置 NLS_LANG 的方法,所以我在 sqlplus 中运行它并确认显示了韩文字符。
如果如下所示将 NLS_LANG 设置为 US7ASCII,则会显示韩语。
C:\Users\ymlee>set NLS_LANG=AMERICAN_AMERICA.US7ASCII C:\Users\ymlee>sqlplus leg/leg@oraus7 SQL*Plus: Release 11.2.0.1.0 Production on Sun Jul 24 21:42:43 2022 Copyright (c) 1982, 2010, Oracle. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production With the Partitioning, OLAP, Data Mining and Real Application Testing options SQL> set pagesize 100 SQL> set linesize 200 SQL> select dbms_lob.getlength(ref_des) chr_len 2 ,lengthb(dbms_lob.substr(ref_des, dbms_lob.getlength(ref_des), 1)) byte_len 3 ,substr(dump(dbms_lob.substr(ref_des, dbms_lob.getlength(ref_des), 1), 1016), 1, 200) dp 4 ,ref_des 5 from sub_mon_stat 6 where ref_des is not null 7 and rownum <= 1 8 SQL> / CHR_LEN BYTE_LEN ---------- ---------- DP -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- REF_DES -------------------------------------------------------------------------------- 3000 3000 Typ=1 Len=3000 CharacterSet=US7ASCII: bc,ad,bf,ef,bf,aa,bc,ad,bf,ef,bf,aa,bc,ad,bf,ef,bf,aa,bc,ad,bf,ef,bf,aa,bc,ad,bf,ef,bf,aa,bc,ad,bf,ef,bf,aa,bc,ad,bf,ef,bf,aa,bc,ad,bf,ef,bf,aa,bc,ad,bf,ef,bf,aa, 서울역서울역서울역서울역서울역서울역서울역서울역서울역서울역서울역서울역서울역서 SQL>
▼ ORAMSWIN949
CLOB数据的字符集为KO16MSWIN949,韩文字符显示正常。
字符数 (chr_len) 为 1,500,字节数 (byte_len) 为 3,000。即可以看出,一个字符存储为2个字节。
▼ 奥特夫
CLOB数据的字符集是AL32UTF8,韩文字符显示正常。
字符数 (chr_len) 为 1,334,字节数 (byte_len) 为 4,000。即可以看出,一个字符存储为3个字节。
(准确的字节数是4002,但略有不同,因为dbms_lob.substr返回的最大字节数是4000)
6.3.2. CLOB 数据转换
CLOB 数据无法通过 DB Link 执行选择。我收到“ORA-22992:无法使用远程表中选定的 LOB 位置”错误。
select use_mon, line_num, sub_sta_id, sub_sta_nm, ride_pasgr_num, alight_pasgr_num, work_dt, commt ,ref_des from sub_mon_stat@dl_us7 a ; ORA-22992: 원격 테이블로 부터 선택된 LOB 위치를 사용할 수 없습니다 22992. 00000 - "cannot use LOB locators selected from remote tables" *Cause: A remote LOB column cannot be referenced. *Action: Remove references to LOBs in remote tables.
您可以使用 CTAS(Create Table As Select)语法复制数据,如下所示。
create table sub_mon_stat_from_oraus7 as select use_mon, line_num, sub_sta_id, sub_sta_nm, ride_pasgr_num, alight_pasgr_num, work_dt ,ref_des from sub_mon_stat@dl_us7 a ; select dbms_lob.getlength(ref_des) chr_len ,lengthb(dbms_lob.substr(ref_des, 1333, 1)) byte_len ,dump(dbms_lob.substr(ref_des, 1333, 1), 1016) dp ,ref_des from sub_mon_stat_from_oraus7 where ref_des is not null and rownum <= 1 ;
看上面的查询执行结果,CLOB列的字符集转换成了AL32UTF8,但是韩文字符串没有正常转换。
在 CLOB 列中转换韩文字符的过程如下。
- 在源数据库中创建一个将 CLOB 列数据类型转换为 BLOB 的视图(实例 #1,ORAUS7)
- 在目标数据库(实例 #3,ORAUTF)中使用 CTAS(Create Table As Select)语法创建表
- 通过将上面创建的表的 BLOB 数据类型转换为 CLOB 类型来创建表
让我们一一看看。
1、在源DB(实例#1,ORAUS7)中创建一个将CLOB列的数据类型转换为BLOB的视图
如果CLOB列的数据类型转换为BLOB,DB Link查询时不转换字符集。
创建一个使用 DBMS_LOB.CONVERTTOBLOB 过程将 CLOB 转换为 BLOB 的函数,如下所示。
CREATE OR REPLACE FUNCTION FN_CLOB_TO_BLOB (P_CLOB CLOB) RETURN BLOB AS L_BLOB BLOB; L_DEST_OFFSET INTEGER := 1; L_SOURCE_OFFSET INTEGER := 1; L_LANG_CONTEXT INTEGER := DBMS_LOB.DEFAULT_LANG_CTX; L_WARNING INTEGER := DBMS_LOB.WARN_INCONVERTIBLE_CHAR; BEGIN IF DBMS_LOB.GETLENGTH(P_CLOB) != 0 THEN DBMS_LOB.CREATETEMPORARY(L_BLOB, TRUE); DBMS_LOB.CONVERTTOBLOB ( DEST_LOB =>L_BLOB, SRC_CLOB =>P_CLOB, AMOUNT =>DBMS_LOB.LOBMAXSIZE, DEST_OFFSET =>L_DEST_OFFSET, SRC_OFFSET =>L_SOURCE_OFFSET, BLOB_CSID =>DBMS_LOB.DEFAULT_CSID, LANG_CONTEXT=>L_LANG_CONTEXT, WARNING =>L_WARNING ); END IF; RETURN L_BLOB; END;
然后,使用上述函数创建一个视图。
出于测试目的,仅选择了某些列和 CLOB 列 REF_DES 中具有值的行。
CREATE OR REPLACE VIEW VW_SUB_MON_STAT_BLOB AS SELECT USE_MON, SUB_STA_ID ,FN_CLOB_TO_BLOB(REF_DES) REF_DES_BLOB FROM SUB_MON_STAT WHERE REF_DES IS NOT NULL;
2.在目标DB(实例#3,ORAUTF)中使用CTAS(Create Table As Select)语法创建表
使用以下语法从 DB Link 获取数据并创建表。
CREATE TABLE SUB_MON_STAT_BLOB AS SELECT A.* FROM VW_SUB_MON_STAT_BLOB@DL_US7 A;
3.创建表,将上面创建的表的BLOB数据类型转换为CLOB类型
创建一个使用 DBMS_LOB.CONVERTTOCLOB 过程将 BLOB 转换为 CLOB 的函数,如下所示。
CREATE OR REPLACE FUNCTION FN_BLOB_TO_CLOB (P_BLOB BLOB) RETURN CLOB AS L_CLOB CLOB; L_DEST_OFFSET INTEGER := 1; L_SOURCE_OFFSET INTEGER := 1; L_LANG_CONTEXT INTEGER := DBMS_LOB.DEFAULT_LANG_CTX; L_WARNING INTEGER := DBMS_LOB.WARN_INCONVERTIBLE_CHAR; BEGIN DBMS_LOB.CREATETEMPORARY(L_CLOB, TRUE); DBMS_LOB.CONVERTTOCLOB ( DEST_LOB =>L_CLOB, SRC_BLOB =>P_BLOB, AMOUNT =>DBMS_LOB.LOBMAXSIZE, DEST_OFFSET =>L_DEST_OFFSET, SRC_OFFSET =>L_SOURCE_OFFSET, --BLOB_CSID =>DBMS_LOB.DEFAULT_CSID, BLOB_CSID =>846, -- NLS_CHARSET_ID('KO16MSWIN949') LANG_CONTEXT=>L_LANG_CONTEXT, WARNING =>L_WARNING ); RETURN L_CLOB; END;
在 DBMS_LOB.CONVERTTOCLOB 过程的参数中,BLOB_CSID 表示“源数据的字符集 ID”。
有关详细信息,请参阅下面的文档。
DBMS_LOB – CONVERTTOCLOB 过程 (oracle.com)
BLOB_CSID 必须指定为整数值,而不是字符串,并且可以通过 NLS_CHARSET_ID 函数获知该值。
由于原始数据的字符集是KO16MSWIN949,执行以下操作确认846。
SELECT NLS_CHARSET_ID('KO16MSWIN949') FROM DUAL;
并且,您可以使用上述功能创建或查询表。
CREATE TABLE SUB_MON_STAT_BLOB_TO_CLOB AS SELECT USE_MON, SUB_STA_ID ,FN_BLOB_TO_CLOB(REF_DES_BLOB) REF_DES FROM SUB_MON_STAT_BLOB A; select * from sub_mon_stat_blob_to_clob ; -- Table 생성하지 않을 경우는 다음과 같이 query 가능 select use_mon, sub_sta_id ,fn_blob_to_clob(ref_des_blob) ref_des from sub_mon_stat_blob ;
您可以检查韩文是否已正常转换,如下所示。
至此,我们已经了解了如何将 US7ASCII 字符集 DB 中包含韩文字符的 CLOB 类型转换为 AL32UTF8。
看起来有点复杂,因为是经过几道工序转换的,但是一步一步看,也没什么难的。
到此为止,关于Oracle字符集转换的系列文章就结束了。
我希望我能对需要它的人有所帮助。