PostgreSQL 10中如何实现MySQL的utf8_general_ci等价排序规则?
作为从MySQL转PostgreSQL的开发者,我完全懂你这种困惑——这俩数据库的字符集和排序规则体系确实不一样,尤其是在Windows环境下的PostgreSQL 10里,默认不会带MySQL那套命名的排序规则。下面给你拆解清楚:
核心差异:PostgreSQL的排序规则逻辑
MySQL的utf8_general_ci是一套预定义的、基于Unicode的通用不区分大小写排序规则;而PostgreSQL的排序规则是和系统区域(locale)绑定的,同时从10版本开始支持ICU(International Components for Unicode)排序规则,命名方式和MySQL完全不同,所以你在pg_collation里找不到utf8_general_ci这类名称是正常的。
最接近的等价方案
根据你的需求,分两种场景给你对应选项:
1. 通用不区分大小写排序(对应utf8_general_ci)
如果不需要针对特定语言的精细排序,只是要类似utf8_general_ci的通用、不区分大小写的行为,推荐使用PostgreSQL的ICU通用排序规则:
- 使用
und-x-icu-ci:代表Unicode通用区域(und)、ICU提供的排序规则、不区分大小写(ci) - 如果还需要不区分重音(类似
utf8_unicode_ci的部分特性),可以用und-x-icu-ci-ai
2. 基于特定语言的排序(更贴近实际业务场景)
如果你的业务主要面向英文用户,那么en_US.UTF-8(Linux/macOS)或者English_United States.65001(Windows)是最常用的UTF-8排序规则,默认是区分大小写的。如果要实现不区分大小写的效果,可以:
- 在字段定义时指定排序规则:
CREATE TABLE users (name VARCHAR(50) COLLATE "en_US.UTF-8"@ucs_basic);(@ucs_basic会使用简单的Unicode码点排序,更接近utf8_general_ci的简化逻辑) - 或者使用PostgreSQL的
citext类型,它会自动以不区分大小写的方式存储和比较字符串:CREATE TABLE users (name CITEXT);
如何查看PostgreSQL中可用的UTF8排序规则
执行以下SQL可以列出所有UTF8编码支持的排序规则:
SELECT collname, collprovider, colllocale FROM pg_collation WHERE collencoding = pg_char_to_encoding('UTF8') ORDER BY collname;
collprovider为icu的是ICU排序规则,libc的是系统locale驱动的规则
创建数据库时指定排序规则
如果你想在创建数据库时就设置全局的排序规则,类似MySQL创建库时指定utf8_general_ci,可以用以下命令:
Linux/macOS
CREATE DATABASE mydb WITH ENCODING 'UTF8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
Windows
CREATE DATABASE mydb WITH ENCODING 'UTF8' LC_COLLATE 'English_United States.65001' LC_CTYPE 'English_United States.65001';
如果要使用ICU的通用不区分大小写规则,可以直接指定:
CREATE DATABASE mydb WITH ENCODING 'UTF8' COLLATE 'und-x-icu-ci';
总结
PostgreSQL没有和utf8_general_ci完全一一对应的排序规则,但通过ICU通用规则或者调整系统locale排序,完全可以实现相同的业务效果。如果是字段级的需求,citext类型也是个非常便捷的选择。
内容的提问来源于stack exchange,提问作者slevin

