为什么 Postgres ORDER BY 似乎中途忽略了前导下划线?

oro*_*aki 8 postgresql order-by postgresql-9.1 natural-sort

我有一个animal带有的表name varchar(255),并且我添加了具有以下值的行:

Piranha
__Starts With 2
Rhino
Starts With 1
0_Zebra
_Starts With 1
Antelope
_Starts With 1
Run Code Online (Sandbox Code Playgroud)

当我运行此查询时:

zoology=# SELECT name FROM animal ORDER BY name;
      name       
-----------------
0_Zebra
Antelope
Piranha
Rhino
_Starts With 1
_Starts With 1
Starts With 1
__Starts With 2
(8 rows)
Run Code Online (Sandbox Code Playgroud)

注意行是如何按顺序排序的,这意味着使用前导__Starts With 1行放在行之前Starts,但__in__Starts With 2似乎忽略了这一事实,好像2末尾比前两个字符更重要。

为什么是这样?

如果我用 Python 排序,结果是:

In  [2]: for animal in sorted(animals):
   ....:     print animal
   ....:     
0_Zebra
Antelope
Piranha
Rhino
Starts With 1
_Starts With 1
_Starts With 1
__Starts With 2
Run Code Online (Sandbox Code Playgroud)

此外,Python 排序建议下划线字母之后,这表明 Postgres 对_Starts行之前的前两行的排序Starts是不正确的。

注意:我使用的是 Postgres 9.1.15

以下是我尝试查找整理的方法:

zoology=# select datname, datcollate from pg_database;
  datname  | datcollate  
-----------+-------------
 template0 | en_US.UTF-8
 postgres  | en_US.UTF-8
 template1 | en_US.UTF-8
 zoology   | en_US.UTF-8
(4 rows)
Run Code Online (Sandbox Code Playgroud)

和:

zoology=# select table_schema, 
    table_name, 
    column_name,
    collation_name
from information_schema.columns
where collation_name is not null
order by table_schema,
    table_name,
    ordinal_position;
 table_schema | table_name | column_name | collation_name 
--------------+------------+-------------+----------------
(0 rows)
Run Code Online (Sandbox Code Playgroud)

dez*_*zso 6

由于您没有为相关列定义不同的排序规则,它使用数据库范围的排序规则,en_US.UTF8就像在我的测试框中一样。我观察到完全相同的行为,将其视为一种安慰:)

我们看到的显然是变量 collat​​ion elements 的一个例子。根据字符和排序规则,许多不同的行为是可能的。这里下划线(以及连字符和其他一些)仅用于打破平局 - 'a' 和 '_a' 在第一轮中是等效的,然后通过考虑下划线来解决它们之间的平局。

如果您想忽略下划线(以及我的示例中的连字符、问号和感叹号)进行排序,您可以定义表达式的排序:

SELECT * 
FROM (VALUES ('a'), 
             ('b1'), 
             ('_a'), 
             ('-a'), 
             ('?a'), 
             ('!a1'), 
             ('a2')
     ) t (val) 
ORDER BY translate(val, '_-?!', '');
Run Code Online (Sandbox Code Playgroud)

在我的实验中,向列表中添加新值通常会改变其他相等项之间的顺序,表明它们被真正平等对待。