更新时间:2024-11-12 GMT+08:00
分享

字符集和字符序合并规则

在MYSQL兼容模式(即sql_compatibility = 'MYSQL')的数据库下,且设置参数b_format_version='5.7'和b_format_dev_version='s2'时,可以将不同字符集字符序的表达式按一定优先级处理,来确定字符串比较运算时的使用的字符序和表达式的字符集。

字符序优先级

不同表达式字符序优先级由高到低排列如下:

  • COLLATE语法拥有最高优先级。

  • 含有字符序冲突的表达式(如:两个不同字符序的字符串拼接表达式)。

  • 支持字符序的数据类型的列、用户自定义变量、存储过程参数、CASE表达式等。

  • 特定的系统函数(如:version()和opengauss_version()函数表达式)。

  • 字符串常量和绑定参数。

  • NULL表达式。

  • 如果一个表达式的数据类型不支持字符序,那么这个表达式的优先级最低。

当两个表达式字符序不同时,使用字符序优先级最高的表达式的字符序。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
gaussdb=# CREATE TABLE t_utf8(c1 varchar(16) character set utf8mb4 collate utf8mb4_bin);
gaussdb=# INSERT INTO t_utf8 VALUES('STRING');

-- 比较时使用utf8mb4_bin字符序,结果为false。
gaussdb=# SELECT c1 = 'string' AS result FROM t_utf8;
 result
--------
 f
(1 row)

-- 比较时使用utf8mb4_general_ci字符序,结果为true。
gaussdb=# SELECT c1 = 'string' COLLATE utf8mb4_general_ci AS result FROM t_utf8;
 result
--------
 t
(1 row)

-- 将绑定参数“$1”的字符序定义为collation_connection。
gaussdb=# PREPARE test_collation(text) AS SELECT c1 = $1 AS result FROM t_utf8;

-- 绑定参数字符序与字符串常量同级别,即使传入的表达式含有显式的字符序,比较时仍然采用c1的字符序。
gaussdb=# EXECUTE test_collation('string' COLLATE utf8mb4_general_ci);
 result
--------
 f
(1 row)

-- CASE表达式与c1列同级别,即使表达式含有显式的字符序,比较时仍然采用c1的字符序,二者不相等,输出“same level”。
gaussdb=# SELECT CASE 'string' COLLATE utf8mb4_general_ci WHEN c1 THEN 'different level' ELSE 'same level' END AS result FROM t_utf8;
   result
------------
 same level
(1 row)

-- IN子查询与c1列同级别,即使表达式含有显式的字符序,比较时仍然采用c1的字符序,二者不相等。
gaussdb=# SELECT c1 FROM t_utf8 WHERE c1 in (SELECT 'string' COLLATE utf8mb4_general_ci);
 c1
----
(0 rows)

当两个相同优先级的表达式字符序不同时,采用以下方式处理:

  • 如果两者字符集相同,优先使用后缀为_bin的字符序。
  • 如果两者字符集相同,优先不使用default字符序。
  • 如果不符合上述情况,两表达式将被标记为字符序冲突,字符序将被标记为无效。
    • 因COLLATE语法指定同字符集不同字符序产生的冲突,将产生异常。

    • 若冲突的两个字符序均为MYSQL模式(即sql_compatibility = 'MYSQL')下支持的字符序,将产生异常。
    • 产生冲突的字符集与数据库字符集server_encoding不同时,将产生异常。

    • 无效字符序如果被用作排序运算时(如:>、<等),将产生异常。
    • 字符串等值比较时,如果字符序无效,将直接作为二进制比较相等。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
gaussdb=# CREATE TABLE t_utf8mb4_charset(
    c_utf8_bin varchar(16) character set utf8mb4 collate utf8mb4_bin,
    c_utf8_uni varchar(16) character set utf8mb4 collate utf8mb4_unicode_ci,
    c_utf8_gen varchar(16) character set utf8mb4 collate utf8mb4_general_ci);
gaussdb=# INSERT INTO t_utf8mb4_charset VALUES('STRING', 'String', 'string');

-- 优先使用utf8mb4_bin字符序比较,结果为false。
gaussdb=# SELECT c_utf8_bin = c_utf8_uni FROM t_utf8mb4_charset;

-- 字符序冲突,进行二进制比较,结果为false。
gaussdb=# SELECT c_utf8_uni = c_utf8_gen FROM t_utf8mb4_charset;

-- 显式指定的字符序冲突,抛出异常。
gaussdb=# SELECT c_utf8_uni COLLATE utf8mb4_unicode_ci = c_utf8_gen COLLATE utf8mb4_general_ci FROM t_utf8mb4_charset;
  • 只有字符串类型(不包括"char"、name、clob)的对象和表达式的字符集可以不同于数据库的字符集。

  • ARRAY、XML、JSON、TSVECTOR等数据类型含有文本数据,这些数据类型的对象和表达式中的文本数据的字符集必须是数据库字符集。
  • 在字符集和字符序合并规则中,认为C、POSIX、DEFAULT字符序对应的字符集为server_encoding。

相关文档