Следуя этому вопросу от Sivaram Chintalapudi, меня интересует, насколько это практично в PostgreSQL сделать естественный - или "очеловеченный" - сортировка" строк, которые содержат смесь многозначных чисел и слов/букв. фиксированный образец слов и чисел в строках, и может быть более одного многозначного числа в строке.
Единственное место, которое я видел, это обычное дело в Mac OS Finder, которое сортирует имена файлов, содержащие смешанные числа и слова, естественно, помещая "20" после "3", а не раньше.
Желаемый порядок сортировки будет создан с помощью алгоритма, который разбивает каждую строку на блоки на границах буквенного номера, затем упорядочивает каждую часть, обрабатывая буквенные блоки с нормальной сортировкой и числовыми блоками как целые числа для целей сопоставления. Итак:
'AAA2fred'
станет ('AAA',2,'fred')
, а 'AAA10bob'
станет ('AAA',10,'bob')
. Затем их можно отсортировать по желанию:
regress=# WITH dat AS ( VALUES ('AAA',2,'fred'), ('AAA',10,'bob') )
regress-# SELECT dat FROM dat ORDER BY dat;
dat
--------------
(AAA,2,fred)
(AAA,10,bob)
(2 rows)
по сравнению с обычным порядком сортировки строк:
regress=# WITH dat AS ( VALUES ('AAA2fred'), ('AAA10bob') )
regress-# SELECT dat FROM dat ORDER BY dat;
dat
------------
(AAA10bob)
(AAA2fred)
(2 rows)
Однако подход сравнения записей не обобщается, поскольку Pg не будет сравнивать конструкции ROW (..) или записи неравных чисел записей.
Учитывая пример данных в этом SQLFiddle, по умолчанию en_AU.UTF-8 сортировка производит упорядочение:
1A, 10A, 2A, AAA10B, AAA11B, AAA1BB, AAA20B, AAA21B, X10C10, X10C2, X1C1, X1C10, X1C3, X1C30, X1C4, X2C1
но я хочу:
1A, 2A, 10A, AAA1BB, AAA10B, AAA11B, AAA20B, AAA21B, X1C1, X1C3, X1C4, X1C10, X1C30, X2C1, X10C10, X10C2
Я работаю с PostgreSQL 9.1 на данный момент, но предложения только 9.2 будут в порядке. Я заинтересован в совете о том, как достичь эффективного метода разделения строк, и как затем сравнить полученные данные разделения в описываемой чередующейся сортировке столбцов с последующим номером. Или, конечно, на совершенно разных и лучших подходах, которые не требуют разделения строк.
PostgreSQL, похоже, не поддерживает функции компаратора, иначе это можно было бы сделать довольно легко с помощью рекурсивного компаратора и что-то вроде ORDER USING comparator_fn
и comparator(text,text)
. Увы, этот синтаксис мнимый.
Обновление: Сообщение в блоге.