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'))
;

每列的数据类型如下。

Oracle Character Set 변환 테스트 테이블 구성
Oracle 字符集转换测试表配置

现在,让我们使用以下 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,韩文字符显示不正常。

ORAUS7 CLOB 데이터 확인
查看ORAUS7 CLOB数据

字符数(chr_len)是3000,字节数(byte_len)也是3000。即可以看出一个字符存储为一个字节。

我找不到在 SQL Developer 中设置 NLS_LANG 的方法,所以我在 sqlplus 中运行它并确认显示了韩文字符。

如果如下所示将 NLS_LANG 设置为 US7ASCII,则会显示韩语。

ORAUS7 CLOB 한글 데이터 확인 (sqlplus, NLS_LANG=US7ASCII)
查看ORAUS7 CLOB韩语数据(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,韩文字符显示正常。

KO16MSWIN949 CLOB 데이터 확인
检查 KO16MSWIN949 CLOB 数据

字符数 (chr_len) 为 1,500,字节数 (byte_len) 为 3,000。即可以看出,一个字符存储为2个字节。

▼ 奥特夫

CLOB数据的字符集是AL32UTF8,韩文字符显示正常。

检查 ORAUTF CLOB 数据

字符数 (chr_len) 为 1,334,字节数 (byte_len) 为 4,000。即可以看出,一个字符存储为3个字节。

(准确的字节数是4002,但略有不同,因为dbms_lob.substr返回的最大字节数是4000)

6.3.2. CLOB 数据转换

CLOB 数据无法通过 DB Link 执行选择。我收到“ORA-22992:无法使用远程表中选定的 LOB 位置”错误。

CLOB 데이터를 DB Link로 query할 때 ORA-22992 오류
使用 DB Link 查询 CLOB 数据时出现 ORA-22992 错误
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,但是韩文字符串没有正常转换。

CTAS로 생성한 Table 데이터 확인
检查使用 CTAS 创建的表数据

在 CLOB 列中转换韩文字符的过程如下。

CLOB 컬럼의 한글을 변환하는 과정 요약
CLOB列中韩文字符转换过程总结
  1. 在源数据库中创建一个将 CLOB 列数据类型转换为 BLOB 的视图(实例 #1,ORAUS7)
  2. 在目标数据库(实例 #3,ORAUTF)中使用 CTAS(Create Table As Select)语法创建表
  3. 通过将上面创建的表的 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。

NLS_CHARSET_ID 함수로 BLOB_CSID 확인
使用 NLS_CHARSET_ID 函数检查 BLOB_CSID
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
;

您可以检查韩文是否已正常转换,如下所示。

CLOB 한글 변환결과 확인
查看 CLOB 韩语转换结果

至此,我们已经了解了如何将 US7ASCII 字符集 DB 中包含韩文字符的 CLOB 类型转换为 AL32UTF8。

看起来有点复杂,因为是经过几道工序转换的,但是一步一步看,也没什么难的。

到此为止,关于Oracle字符集转换的系列文章就结束了。

我希望我能对需要它的人有所帮助。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

zh_CN简体中文