Буквенно-цифровая сортировка с помощью 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]*$')
вы должны добавить новый столбец в базу данных, которая имеет числовой тип данных, и при сохранении новой записи установите для него то же значение, что и префикс в строковом значении.
затем вы можете создать индекс на правильно введенный числовой столбец для сортировки.