Неверная сортировка PostgreSQL
Я использую PostgreSQL 9.3.3, и у меня есть таблица с одним столбцом с именем title (символ меняется (50)).
Когда я выполнил следующий запрос:
select * from test
order by title asc
Я получил следующие результаты:
#
A
#Example
Почему "#Example" находится в последней позиции? По-моему, "#Example" должен быть во второй позиции.
Ответы
Ответ 1
Тип сортировки для текста (включая char
и varchar
, а также тип text
) зависит от текущей сортировки вашей локали.
См. предыдущие тесно связанные вопросы:
Если вы хотите сделать упрощенную сортировку по значению ASCII, а не по правильной локализованной сортировке, следуя вашим правилам локального языка, вы можете использовать COLLATE
пункт
select *
from test
order by title COLLATE "C" ASC
или изменить глобальную сортировку базы данных (требуется сброс и перезагрузка, или полное переиндексация). В моей Linux-системе Fedora 19 я получаю следующие результаты:
regress=> SHOW lc_collate;
lc_collate
-------------
en_US.UTF-8
(1 row)
regress=> WITH v(title) AS (VALUES ('#a'), ('a'), ('#'), ('a#a'), ('a#'))
SELECT title FROM v ORDER BY title ASC;
title
-------
#
a
#a
a#
a#a
(5 rows)
regress=> WITH v(title) AS (VALUES ('#a'), ('a'), ('#'), ('a#a'), ('a#'))
SELECT title FROM v ORDER BY title COLLATE "C" ASC;
title
-------
#
#a
a
a#
a#a
(5 rows)
PostgreSQL использует поддержку сопоставления операционной системы, поэтому результаты могут незначительно отличаться от ОС хоста к ОС хоста. В частности, по крайней мере некоторые версии Mac OS X значительно нарушили обработку сортировки unicode.
Ответ 2
Кажется, что при сортировке Oracle, а также Postgres просто игнорируют неаполя числовые символы, например
select '*'
union all
select '#'
union all
select 'A'
union all
select '*E'
union all
select '*B'
union all
select '#C'
union all
select '#D'
order by 1 asc
возвращает (посмотрите: что СУБД не обращает внимания на префикс до "A".. "E" )
*
#
A
*B
#C
#D
*E
В вашем случае, что действительно создает Postgres,
''
, 'A'
и 'Example'
Если вы поместите '#'
в середине строки, поведение будет таким же:
select 'A#B'
union all
select 'AC'
union all
select 'A#D'
union all
select 'AE'
order by 1 asc
возвращает (#
игнорируется, и поэтому 'AB', 'AC', 'AD'
и 'AE'
фактически сравниваются)
A#B
AC
A#D
AE
Чтобы изменить правила сравнения, вы должны использовать сортировка, например
select '#' collate "POSIX"
union all
select 'A' collate "POSIX"
union all
select '#Example' collate "POSIX"
order by 1 asc
возвращает (как требуется в вашем случае)
#
#Example
A