Буквенно-цифровая сортировка с помощью PostgreSQL
в базе данных, у меня есть различные буквенно-числовые строки в следующем формате:
10_asdaasda
100_inkskabsjd
11_kancaascjas
45_aksndsialcn
22_dsdaskjca
100_skdnascbka
Я хочу, чтобы они по существу были отсортированы по номеру перед строкой, а затем само имя строки, но, конечно, символы сравниваются один за другим, и поэтому результат порядка по имени производит:
10_asdaasda
100_inkskabsjd
100_skdnascbka
11_kancaascjas
22_dsdaskjca
45_aksndsialcn
вместо заказа я бы предпочел:
10_asdaasda
11_kancaascjas
22_dsdaskjca
45_aksndsialcn
100_inkskabsjd
100_skdnascbka
честно говоря, я был бы в порядке, если бы строки были просто отсортированы по номеру впереди. Я не слишком хорошо знаком с PostgreSQL, поэтому я не был уверен, что это лучший способ сделать. Я был бы признателен за любую помощь!
4 ответов
идеальным способом было бы нормализуют ваши данные и разделить два компонента столбца на два отдельных столбца. Один из типа integer
, одно text
.
С текущей таблицей, вы можете сделать что-то, как показано здесь:
WITH x(t) AS (
VALUES
('10_asdaasda')
,('100_inkskabsjd')
,('11_kancaascjas')
,('45_aksndsialcn')
,('22_dsdaskjca')
,('100_skdnascbka')
)
SELECT t
FROM x
ORDER BY (substring(t, '^[0-9]+'))::int -- cast to integer
,substring(t, '[^0-9_].*$') -- works as text
то же самое substring()
выражения можно использовать для разделения столбца.
регулярные выражения несколько отказоустойчивость:
первый regex выбирает самую длинную числовую строку слева,
NULL
если цифры не найдены, поэтому приведение кinteger
не ошибетесь.второе регулярное выражение выбирает остальную часть строки из первого символа, который не является цифрой или"_".
если подчеркивание однозначно как разделитель в любом случае,split_part()
быстрее:
ORDER BY (split_part(t, '_', 1)::int
,split_part(t, '_', 2)
ответ на ваш пример
SELECT name
FROM nametable
ORDER BY (split_part(name, '_', 1)::int
,split_part(name, '_', 2)
есть способ сделать это с показателем за выражение. Это не было бы моим предпочтительным решением (я бы пошел на Брэда), но вы можете создать индекс на следующем выражении (есть больше способов сделать это):
CREATE INDEX idx_name ON table (CAST(SPLIT_PART(columname, '_', 1) AS integer));
тогда вы можете искать и заказывать по CAST(SPLIT_PART(columname, '_', 1) AS integer)
каждый раз, когда вам нужно число перед символом подчеркивания, например:
SELECT * FROM table ORDER BY CAST(SPLIT_PART(columname, '_', 1) AS integer);
вы можете сделать то же самое со Строковой частью, создав индекс на SPLIT_PART(columname, '_', 2)
, а затем отсортировать соответственно как что ж.
Однако, как я уже сказал, Я нахожу это решение очень уродливым. Я бы определенно пошел с двумя другими столбцами (один для числа и один для строки), а затем, возможно, даже удалил столбец, который вы упоминаете здесь.
вы можете использовать регулярные выражения с подстроки
order by substring(column, '^[0-9]+')::int, substring(column, '[^0-9]*$')
вы должны добавить новый столбец в базу данных, которая имеет числовой тип данных, и при сохранении новой записи установите для него то же значение, что и префикс в строковом значении.
затем вы можете создать индекс на правильно введенный числовой столбец для сортировки.