Неверная сортировка 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