PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Хуманизирано или естествено сортиране на числа от смесени низове от думи и числа

Въз основа на вашите тестови данни, но това работи с произволни данни. Това работи с произволен брой елементи в низа.

Регистрирайте съставен тип, съставен от един 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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. DROP FUNCTION без да знаете броя/вида на параметрите?

  2. INSERT COMMAND ::ГРЕШКА:стойността на колоната не съществува

  3. Spring Batch - Не може да се създадат таблици с метаданни на Postgres и да се заредят действителни данни в mysql

  4. Актуализирайте множество колони в тригерна функция в plpgsql

  5. Как да нулирате последователността на първичния ключ на postgres, когато не е синхронизирана?