更新时间:2025-09-12 GMT+08:00
分享

字符集和字符序合并规则

不同字符集字符序的表达式按一定优先级处理,来确定字符串比较运算时的使用的字符序和表达式的字符集。

字符序优先级

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

  • 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
40
m_db=# CREATE TABLE t_utf8(c1 varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin);
m_db=# INSERT INTO t_utf8 VALUES('STRING');

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

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

-- 将绑定参数“?”的字符序定义为collation_connection。
m_db=# PREPARE test_collation FROM 'SELECT c1 = ? AS result FROM t_utf8';

-- 绑定参数字符序与字符串常量同级别,在上一步prepare时已经确定了执行时使用c1的字符序,因此结果为false。
m_db=# SET @aa = 'string' COLLATE utf8mb4_general_ci;
m_db=# EXECUTE test_collation using @aa;
 result
--------
 f
(1 row)

-- CASE表达式与c1列同级别,即使表达式含有显式的字符序,比较时仍然采用c1的字符序,二者不相等,输出“same level”。
m_db=# 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的字符序,二者不相等。
m_db=# SELECT c1 FROM t_utf8 WHERE c1 in (SELECT 'string' COLLATE utf8mb4_general_ci);
 c1
----
(0 rows)

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

  • 如果两者字符集相同,优先使用后缀为_bin的字符序。
  • 如果两者字符集相同,优先不使用default字符序。
  • 如果两者字符集不同,优先使用BINARY字符序。
  • 如果两者字符集不同,且一个为Unicode字符集,另一个不为Unicode字符集,非Unicode字符集的表达式需要转码为Unicode字符集,最终使用Unicode字符集的表达式的字符序。
  • 如果不符合上述情况,两表达式将被标记为字符序冲突,字符序将被标记为无效。
    • 因COLLATE语法指定同字符集不同字符序产生的冲突,将提示异常。

    • 若相同字符集的字符序由于没有_bin字符序产生冲突,在字符串拼接函数中会使用该字符集的_bin字符序,并且该_bin字符序也仅能用于字符串拼接,其他使用场景将提示异常。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
m_db=# 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);
m_db=# INSERT INTO t_utf8mb4_charset VALUES('STRING', 'String', 'string');

-- 优先使用utf8mb4_bin字符序比较,结果为false。
m_db=# SELECT c_utf8_bin = c_utf8_uni FROM t_utf8mb4_charset;
 ?column?
----------
 f
(1 row)

-- 字符序冲突,进行二进制比较,结果为false。
m_db=# SELECT c_utf8_uni = c_utf8_gen FROM t_utf8mb4_charset;
ERROR:  Collation mismatch between collations "utf8mb4_unicode_ci" and "utf8mb4_general_ci".
LINE 1: SELECT c_utf8_uni = c_utf8_gen FROM t_utf8mb4_charset;
                            ^

-- 显式指定的字符序冲突,抛出异常。
m_db=# SELECT c_utf8_uni COLLATE utf8mb4_unicode_ci = c_utf8_gen COLLATE utf8mb4_general_ci FROM t_utf8mb4_charset;
ERROR:  collation mismatch between explicit collations "utf8mb4_unicode_ci" and "utf8mb4_general_ci"
LINE 1: ..._utf8_uni COLLATE utf8mb4_unicode_ci = c_utf8_gen COLLATE ut...
                                                             ^
  • 只有字符串类型(包括SET、ENUM类型)的对象和表达式的字符集可以和数据库的字符集不同。

  • 在字符集和字符序合并规则中,认为 C、POSIX、DEFAULT字符序对应的字符集为server_encoding。

相关文档