PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Humanizowane lub naturalne sortowanie mieszanych ciągów słów i liczb

Opierając się na danych testowych, ale działa to z dowolnymi danymi. Działa to z dowolną liczbą elementów w ciągu.

Zarejestruj typ złożony składający się z jednego text i jedna integer wartość raz na bazę danych. Nazywam to ai :

CREATE TYPE ai AS (a text, i int);

Sztuczka polega na utworzeniu tablicy ai z każdej wartości w kolumnie.

regexp_matches() ze wzorem (\D*)(\d*) i g opcja zwraca jeden wiersz dla każdej kombinacji liter i cyfr. Plus jeden nieistotny wiszący wiersz z dwoma pustymi ciągami '{"",""}' Filtrowanie lub tłumienie tylko zwiększałoby koszty. Zagreguj to do tablicy, po zastąpieniu pustych ciągów ('' ) z 0 w integer komponent (jako '' nie można rzutować na integer ).

NULL wartości najpierw posortuj - lub musisz umieścić je w specjalnej wielkości - lub użyj całego zbioru w STRICT funkcjonować tak, jak proponuje @Craig.

Postgres 9.4 lub nowszy

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<>graj tutaj

Postgres 9.1 (oryginalna odpowiedź)

Testowane z PostgreSQL 9.1.5, gdzie regexp_replace() miał nieco inne zachowanie.

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

Dodaj regexp_replace (left(data, 1), '[1-9]', '0') jako pierwszy ORDER BY element do obsługi wiodących cyfr i pustych ciągów.

Jeśli znaki specjalne, takie jak {}()"', może wystąpić, musisz odpowiednio uciec przed nimi.
Sugestia @Craiga, aby użyć ROW express o to zadba.

BTW, to nie zostanie wykonane w sqlfiddle, ale działa w moim klastrze db. JDBC nie jest do tego zdolne. sqlfiddle narzeka:

Metoda org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) nie została jeszcze zaimplementowana.

Zostało to naprawione: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. Moje ulubione rozszerzenia PostgreSQL — część pierwsza

  2. Jak wyodrębnić numer tygodnia z daty w PostgreSQL?

  3. Analiza porównawcza zarządzanych rozwiązań PostgreSQL w chmurze:część druga — Amazon RDS

  4. Jak określić ostatni dzień poprzedniego miesiąca za pomocą PostgreSQL?

  5. PostgreSQL działa wolno? Wskazówki i porady, jak dotrzeć do źródła