
# 使用GB18030字符集解决生僻字和少数民族文字无法识别问题
在业务日常开发过程中处理中文文本时，我们经常遇到GBK字符集由于字符范围有限，导致生僻字和少数民族文字无法正确识别的问题，这不仅影响了用户体验，也不符合《信息技术产品国家通用语言文字使用管理规定》的要求。
为了解决这一问题，DWS在**9.1.1.100版本** **新增支持了** **GB18030字符集** **功能**，支持更广泛字符集的编码方式，它能够覆盖绝大部分的字符，包括生僻字和少数民族文字，从而满足国家规定的要求，同时提升用户体验。
#### 约束限制
**该功能仅9.1.1.100及以上的集群版本支持。**
#### GB18030编码介绍
GB18030采用1/2/4字节变长编码结构，对应的编码范围如[表1]所示。
 表1GB18030编码结构 
| 字节数 | 编码范围                                    | 字符类型           |
|:---|:---|:---|
| 1字节 | 0x00-0x7F                               | ASCII兼容字符      |
| 2字节 | 0x81-0xFE 0x40-0x7E/0x80-0xFE           | 基本汉字区(20902字)  |
| 4字节 | 0x81-0xFE 0x30-0x39 0x81-0xFE 0x30-0x39 | 扩展区(70,000+汉字) |
   
常用汉字编码示例：
```
"中" -> 0xD6D0 (2字节)
"䶮" -> 0x9835FC39 (4字节)
"𠀀" -> 0x90308130 (4字节, CJK扩展B区)
```
GB18030版本演进情况如[表2]所示：
 表2版本演进 
| 特性          | GB18030-2000 | GB18030-2005 | GB18030-2022 |
|:---|:---|:---|:---|
| 汉字数量        | 27,533       | 70,244       | 87,887       |
| 支持Unicode版本 | 3.0          | 4.0          | 11.0         |
| 新增字符        | CJK扩展A       | CJK扩展B       | CJK扩展C-G     |
| 少数民族文字      | 基本支持         | 增强支持         | 完整支持         |
| 部首支持        | 无            | 无            | 228部首        |
   
GB18030相比于GBK字符集，在支持汉字数量和种类上，都有明显扩展。
表3GB18030与GBK对比 
| 维度        | GBK     | GB18030       |
|:---|:---|:---|
| 编码空间      | 23940字符 | 160万+字符       |
| 字节结构      | 固定双字节   | 1/2/4字节变长     |
| Unicode映射 | 部分支持    | 完全支持          |
| 生僻字支持     | \< 10%  | 100%覆盖        |
| 少数民族文字    | 不支持     | 完整支持(苗文、傈僳文等) |
| Emoji支持   | 无       | 完整支持(✅等)      |
   
#### DWS对GB18030的支持范围
- **字符集**：完整支持87,887汉字+228部首
- **少数民族文字** ：
  - 滇东北苗文 (U+16F00-U+16F9F)
  
  - 傈僳文 (U+A4D0-U+A4FF)
  
  - 西夏文 (U+17000-U+187FF)
   
- **特殊符号** ：
  - 易经八卦符号 (U+4DC0-U+4DFF)
  
  - 太玄经符号 (U+1D300-U+1D35F)
  
  - 麻将牌符号 (U+1F000-U+1F02F)
   
 
#### 基本创建语法
创建字符集编码为GB18030的数据库。
```
CREATE DATABASE gb18030_db
    ENCODING = 'GB18030'
    LC_COLLATE = 'zh_CN.GB18030'
    LC_CTYPE = 'zh_CN.GB18030'
    DBCOMPATIBILITY = 'TD'
    TEMPLATE = template0;
```
- **LC_COLLATE**: 指定数据库使用的字符集。例如，gbk编码通过lc_collate='zh_CN.gbk'，utf8通过lc_collate='en_us.utf8'，gb18030/gb18030-2022通过lc_collate='zh_CN.GB18030'。该参数的使用会影响到对字符串的排序顺序，可以通过查pg_collate表找到对应编码的lc_collate。
- **LC_CTYPE**：指定新数据库使用的字符分类。例如，通过lc_ctype = 'zh_CN.gbk'设定该参数。该参数的使用会影响到字符的分类，如大写、小写和数字。默认是使用模板数据库的字符分类。
- **ENCODING**：指定数据库字符集，固定为GB18030。
- **DBCOMPATIBILITY**：兼容Teradata语法。
创建支持GB18030的表。
```
-- 普通表
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50) NOT NULL COLLATE "zh_CN.gb18030",
    id_card CHAR(18) COLLATE "zh_CN.gb18030"
);
-- 分区表示例
CREATE TABLE census_data (
    region_code CHAR(6),
    family_name VARCHAR(20) COLLATE "zh_CN.gb18030",
    population INT
) PARTITION BY range(population)
(PARTITION p1 START(1) END(10) EVERY(1));
```
为特定列设置排序规则。
```
ALTER TABLE users 
ALTER COLUMN name TYPE VARCHAR(50) COLLATE "zh_CN.gb18030";
```
查看当前排序规则。
```
SELECT a.attname, c.collname 
FROM pg_attribute a
JOIN pg_collation c ON a.attcollation = c.oid
WHERE a.attrelid = 'users'::regclass;
```
#### 使用场景：插入和查询生僻字
1. 创建字符集编码为GB18030的数据库。 
   ```
   CREATE DATABASE gb18030_db
       ENCODING = 'GB18030'
       LC_COLLATE = 'zh_CN.GB18030'
       LC_CTYPE = 'zh_CN.GB18030'
       DBCOMPATIBILITY = 'TD'
       TEMPLATE = template0;
   ```
   
   
2. 连接到新创建的gb18030_db数据库下，创建测试表rare_characters。 
   ```
   CREATE TABLE rare_characters (
       id SERIAL PRIMARY KEY,
       character TEXT COLLATE "zh_CN.gb18030",
       unicode_point VARCHAR(10)
   );
   ```
   
   
3. 设置客户端字符编码为GB18030。 
   ```
   SET client_encoding = 'GB18030';
   ```
   
   
4. 插入生僻字。 
   ```
   INSERT INTO rare_characters (character, unicode_point) VALUES
   ('䶮', 'U+4DAE'), -- GB18030编码: 0x9835FC39
   ('𰾅', 'U+30F85'),-- CJK扩展G区
   ('', 'U+31350'); -- 傈僳文字符
   ```
   
   
5. 查询验证。 
   ```
   SELECT * FROM rare_characters  WHERE character = '䶮';
   ```
   
   
 
#### GDS数据迁移流程
本样例重点突出GDS外表样例，详细GDS外表迁移流程参见[使用GDS从远端服务器上导入表数据到DWS集群](https://support.huaweicloud.com/bestpractice-dws/dws_05_0032.html)。
1. 启动GDS服务。 
   ```
   gds -d /data/gds_dir -p ip:port -H address_string -l log_file -D -t worker_num
   ```
   
   
2. 创建GDS外表，其中字符集编码encoding设置成GB18030。 
   ```
   CREATE FOREIGN TABLE gb18030_import (
       id INT,
       full_name TEXT,
       address TEXT
   ) SERVER gsmpp_server OPTIONS (
       location 'gsfs://ip:port/filepwd',
       format 'text',
       delimiter '|',
       encoding 'GB18030',
       compatible_illegal_chars 'true',
       replace_illegal_chars '',
       fill_missing_fields 'true',
       ignore_extra_data 'true',
       noescaping 'on'
   );
   ```
   
   
3. 导入目标表。 
   ```
   CREATE TABLE citizens AS  SELECT * FROM gb18030_import;
   ```
   
   
4. 验证数据。 
   ```
   SELECT count(*) FROM citizens;SELECT * FROM citizens WHERE full_name LIKE '%䶮%';
   ```
   
   
5. 导出数据。 
   ```
   CREATE FOREIGN TABLE gds_out
   (
       a int not null,
       b text;
       c text;
   )SERVER gsmpp_server
       OPTIONS(location 'gsfs://ip:port',
       format 'text',
       delimiter ',',
       compatible_illegal_chars 'True',
       REPLACE_ILLEGAL_CHARS ' '
   ) WRITE ONLY;
   INSERT INTO gds_out SELECT * FROM t1 ORDER BY a;
   ```
   
   
 
#### 字符编码相关函数
```
-- 二进制转文本
SELECT convert_from('\x8149', 'GB18030') AS chinese_char; -- 输出：'両'
-- 文本转二进制
SELECT convert_to('华为', 'GB18030') AS byte_stream; -- 输出：\xBBAACC
-- 编码间转换
SELECT convert('\x8149', 'GB18030', 'UTF8') AS utf8_bytes;
-- 获取字符数（非字节数）
SELECT char_length('中文䶮'); -- 返回3（3个字符）
-- 按字符截取
SELECT substring('中文䶮云朵', 3, 2); -- 返回'䶮云'
-- 四字节字符处理
SELECT overlay('ABCDEF' 
               PLACING '䶮' 
               FROM 3 FOR 2); -- 返回'AB䶮EF'
```
#### 常见问题
- **如何检查数据库当前字符集？**
  ```
  -- 查看数据库编码
  SELECT datname, pg_encoding_to_char(encoding) 
  FROM pg_database;
  SHOW service_encoding;
  -- 查看客户端编码
  SHOW client_encoding;
  ```
  
- **插入时遇到"invalid byte sequence"错误？**
  该字符的码位不支持。
  
 
#### 更多文档
- [CREATE DATABASE](https://support.huaweicloud.com/sqlreference-911-dws/dws_06_0156.html)
- [CREATE TABLE](https://support.huaweicloud.com/sqlreference-911-dws/dws_06_0177.html)
- [如何查看和设置DWS数据库的字符集编码格式](https://support.huaweicloud.com/dws_faq/dws_03_0085.html)
- [字符串处理函数和操作符](https://support.huaweicloud.com/sqlreference-dws/dws_06_0030.html)
 
