Oracle, PostgreSQL 字符串排序不一致及调整

有一个使用了不同数据库的应,Oracle 和 PostgreSQL,数据库中的记录完全相同,相同的查询语句(相同的排序,至少从字面上来说是的)取到的记录排序却不同,从而产生了 Bug。 简单演示一下默认排序各自在这两种数据库中的行为, 比如说表中有两条记录,'VFORX' 和 'ibbVA'。此处不创建物理表。

Oracle(Linux)

select * from (
    select 'VFORX' as value from dual
        union
    select 'ibbVA' from dual
) order by 1 desc;

返回的结果是

PostgreSQL(Linux)

得到的不同的排序结果

程序中只是简单的使用第一条记录的值,当然程序是有 Bug 的,这是外话。

能立即让它们行为一致的方式是保证排序后结果一致,在 PostgreSQL 中排序时指定 collate "POSIX" 或 "C"

collate "C" 也能得到一样的效果

问题是解决了,从中也领悟了 collate 在数据库以及排序中的作用。以前隐约记得在创建数据库时不仅要指定数据库使用的字符集,也就是存储所采用的字符集,还会指定一个叫做 collate 的东西,当时并未太在意它意味着什么,而碰到问题后才想起它的重要。

collate 是定义字符集排序规则的关键字,如区不区分大小写,或按照某种语言的自然顺序。现在也回想起为什么 MySQL 的 varchar 类型默认不区分大小写,字段的值是 'AaB', 用 where a = 'aab' 也能查询出来的缘故。

PostgreSQL 中如何指定 collate

看到

datcollate 也是 en_US.UTF-9, 我们可以在创建数据库时候指定 LC_COLLATE = 'C'

执行上面语句时还必须指定 TEMPLATE = template0, 否则有错。数据库创建后再查看

datcollate 和 datctype 就变成了

切换数据库到 mydb 后

就变成了

或者表的字段级指定 collate 类型

Oracle 数据库如何指琮 collate

Oracle 12.2 也开始支持 Schema, 表,列级别的 collate

执行上面的语句大概率会出现如下错语

SQL Error [43929] [99999]: ORA-43929: Collation cannot be specified if parameter MAX_STRING_SIZE=STANDARD is set.

看到的是 STANDARD

需修改成 extended 才行

再重启数据库

SHUTDOWN IMMEDIATE;
STARTUP UPGRADE;

Oracle 通常默认的 collate 是 BINARY, 由 NLS_COMP 和 NLS_SORT, NLS_LANGUAGE, NLS_TERRITORY 等决定的

假如

返回 NULL 的话就是用了默认的 collation.

Oracle 的 collate 可应用到 VARCHAR2, CHAR, CLOB, 可选值有

  1. COLLATE BINARY:  基于二进制,排序最快,大小写敏感
  2. COLLATE BINARY_CI: Case Insensitive, 比较时(如 >, <, =) 时大小写不敏感,但排序时区分大小写
  3. COLLATE BINARY_AI: Accent Insensitive, 比较和排序时都不区分大小写

本文链接 https://yanbin.blog/oracle-postgresql-string-sorting-different-consistent/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments