Въз основа на вашите тестови данни, но това работи с произволни данни. Това работи с произволен брой елементи в низа.
Регистрирайте съставен тип, съставен от един text
и едно integer
стойност веднъж на база данни. Наричам го ai
:
CREATE TYPE ai AS (a text, i int);
Номерът е да се формира масив от ai
от всяка стойност в колоната.
regexp_matches()
с шаблона (\D*)(\d*)
и g
опцията връща един ред за всяка комбинация от букви и цифри. Плюс един неуместен висящ ред с два празни низа '{"",""}'
Филтрирането или потискането му само би увеличило разходите. Обединете това в масив, след като замените празните низове (''
) с 0
в integer
компонент (като ''
не може да бъде прехвърлен към integer
).
NULL
стойностите първо сортирайте - или трябва да ги поставите в специален случай - или използвайте целия шебан в STRICT
функция, както предлага @Craig.
Postgres 9.4 или по-нова версия
SELECT data
FROM alnum
ORDER BY ARRAY(SELECT ROW(x[1], CASE x[2] WHEN '' THEN '0' ELSE x[2] END)::ai
FROM regexp_matches(data, '(\D*)(\d*)', 'g') x)
, data;
db<>цигулка тук
Postgres 9.1 (оригинален отговор)
Тествано с PostgreSQL 9.1.5, където regexp_replace()
имаше малко по-различно поведение.
SELECT data
FROM (
SELECT ctid, data, regexp_matches(data, '(\D*)(\d*)', 'g') AS x
FROM alnum
) x
GROUP BY ctid, data -- ctid as stand-in for a missing pk
ORDER BY regexp_replace (left(data, 1), '[0-9]', '0')
, array_agg(ROW(x[1], CASE x[2] WHEN '' THEN '0' ELSE x[2] END)::ai)
, data -- for special case of trailing 0
Добавете regexp_replace (left(data, 1), '[1-9]', '0')
като първи ORDER BY
елемент, който се грижи за водещите цифри и празните низове.
Ако специални знаци като {}()"',
може да възникне, ще трябва да ги избягате съответно.
Предложение на @Craig за използване на ROW
Expression се грижи за това.
BTW, това няма да се изпълни в sqlfiddle, но се изпълнява в моя db клъстер. JDBC не е до това. sqlfiddle се оплаква:
Методът org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) все още не е внедрен.
Оттогава това беше коригирано:http://sqlfiddle.com/#!17/fad6e/1