如何构建一个Python比较器,以PostgreSQL的方式对字符串进行排序?

时间:2019-01-06 16:48:59

标签: python postgresql collation

这个问题与this question基本上相同,除了Python。

我希望从按电子邮件地址列排序的PostgreSQL数据库中查询行,然后在Python中执行依赖该排序的操作。

我正在查询的数据库正在使用en_US.UTF8归类,通过一些测试,我发现相对于电子邮件地址中的@符号有一些特殊的行为:

mydb=> SELECT '0'  < '@';
 ?column? 
----------
 f
(1 row)

mydb=> SELECT '0'  < '@0';
 ?column? 
----------
 t
(1 row)

This answer建议在某些排序规则中忽略@符号,但是如果是这种情况,我希望第二个查询中出现t

尽管Python提供了locale module,但该模块具有inconsistent behavior on some platforms,所以我似乎无法为此目的使用该模块。

基于该报告,我尝试了使用PyICU package的建议,该建议似乎很有希望:

>>> import icu
>>> collator = icu.Collator.createInstance()
>>> collator.getLocale()
<Locale: en_US>
>>> collator.getSortKey('0') < collator.getSortKey('@')
False
>>> collator.getSortKey('0') < collator.getSortKey('@0')
False

但是您可以看到,在最后一次比较中,它产生的顺序与postgres的顺序不同。

我尝试为查询指定其他排序规则,例如:

SELECT email COLLATE posix FROM mytable ORDER by email;

但这会导致错误:collation "posix" for encoding "UTF8" does not exist。我还尝试了"en-us-x-icu"的排序规则,但该排序规则也不存在。

是否有任何方法可以通过适应查询的排序规则或遵循Python中的默认排序规则,以Python程序可以依赖的顺序可靠地从PostgreSQL查询电子邮件地址列?

1 个答案:

答案 0 :(得分:1)

在Postgres中使用collate "C"

with test(test) as (
values ('@'), ('@0'), ('0')
)

select test
from test
order by test collate "C"

 test 
------
 0
 @
 @0
(3 rows)

Python:

>>> test = ['@', '@0', '0']
>>> test.sort()
>>> test
['0', '@', '@0']