PostgreSQL игнорирует тире при заказе

У меня есть база данных PostgreSQL 8.4, созданная с локалью da_DK.utf8.

dbname=> show lc_collate;
 lc_collate
------------
 da_DK.utf8
(1 row)

Когда я выбираю что-то из таблицы, где я заказываю столбец с переменным символом, я получаю странное поведение IMO. При упорядочивании результата PostgreSQL игнорирует дефисы перед значением, например:

 select name from mytable order by name asc;

Может вернуть что-то вроде

 name
 ----------------
 Ad...
 Ae...
 Ag...
 - Ak....
 At....

Префикс тире, кажется, игнорируется.

Я могу исправить эту проблему, преобразовав столбец в latin1 при заказе:

 select name from mytable order by convert_to(name, 'latin1') asc;

Я получаю ожидаемый результат как:

 name
 ----------------
 - Ak....
 Ad...
 Ae...
 Ag...
 At....

Почему префикс тире по умолчанию игнорируется? Можно ли изменить это поведение?


person HakonB    schedule 10.02.2011    source источник
comment
Какую ОС вы используете? Он отлично работает в Windows 7, convert_to() не требуется.   -  person Frank Heikens    schedule 10.02.2011
comment
Я использую сервер Ubuntu 10.10, а PostgreSQL версии 8.4.7, если быть точным.   -  person HakonB    schedule 10.02.2011


Ответы (3)


Это связано с тем, что локаль da_DK.utf8 определяет его таким образом. Утилиты, поддерживающие локаль Linux, например sort, также будут работать так.

Ваш convert_to(name, 'latin1') сломается, если найдет символ, который не входит в набор символов Latin 1, например , так что это не лучший обходной путь.

Вы можете использовать order by convert_to(name, 'SQL_ASCII'), который будет игнорировать сортировку, определенную локалью, и просто использовать байтовые значения.


Уродливое редактирование взлома:

order by
  (
    ascii(name) between ascii('a') and ascii('z')
    or ascii(name) between ascii('A') and ascii('Z')
    or ascii(name)>127
  ),
  name;

Это сначала отсортирует все, что начинается с ASCII-буквы. Это очень некрасиво, потому что дальнейшая сортировка в строке будет вести себя странно, но для вас это может быть достаточно хорошо.

person Tometzky    schedule 10.02.2011
comment
Я как бы знал, что преобразование в latin1 что-то сломает, но мне действительно нужен правильный датский порядок сортировки, где, например, double-a («aa») будет сортироваться последним после «z». - person HakonB; 10.02.2011
comment
Мне больше нравится решение translate(name, '-', '!') , так как оно решает мою проблему, не будучи сложным для запоминания :-) - person HakonB; 10.02.2011

Обходной путь, который будет работать в моем конкретном случае, — заменить тире восклицательными знаками. Я знаю, что у меня никогда не будет восклицательных знаков, и они будут отсортированы перед любыми буквами или цифрами.

select name from mytable order by translate(name, '-', '!') asc

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

person HakonB    schedule 10.02.2011

Я не знаю, как выглядят правила упорядочения для голландского языка, но для польского специальные символы, такие как пробел, тире и т. д., не «учитываются» при сортировке в большинстве словарей. Некоторые хорошие процедуры сортировки делают то же самое и игнорируют такие специальные символы. Вероятно, в голландском языке есть аналогичное правило, и это правило реализуется функцией сортировки с учетом локали Ubuntu.

person Michał Niklas    schedule 10.02.2011