Как создать компаратор Python, который сортирует строки так, как это делает PostgreSQL? - PullRequest
0 голосов
/ 06 января 2019

Этот вопрос по сути такой же, как этот вопрос , за исключением Python.

Я хочу запросить строки из базы данных PostgreSQL, упорядоченные по столбцу адреса электронной почты, а затем выполнить операции на Python, основанные на этом порядке.

В базе данных, которую я запрашиваю, используется сопоставление en_US.UTF8, которое, как я обнаружил, с помощью нескольких тестов ведет себя по отношению к символу @ в адресах электронной почты:

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

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

Этот ответ предполагает, что символ @ может игнорироваться некоторыми сопоставлениями, но если бы это было здесь, я бы ожидал t от второго запроса.

Хотя Python предоставляет языковой модуль , этот модуль имеет несовместимое поведение на некоторых платформах , поэтому я не могу использовать этот модуль для этой цели.

На основании этого отчета я попытался рекомендовать использовать пакет PyICU , который показался многообещающим:

>>> 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", но оно также не существует.

Есть ли способ надежно запросить столбец адресов электронной почты из PostgreSQL в порядке, на который могла бы положиться программа Python, либо адаптировав параметры сортировки запроса, либо соблюдая параметры сортировки по умолчанию в Python?

1 Ответ

0 голосов
/ 06 января 2019

Использование collate "C" в Postgres:

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']    
...