sql >> Database teknologi >  >> RDS >> PostgreSQL

Humaniseret eller naturlig nummersortering af blandede ord-og-tal-strenge

Bygger på dine testdata, men dette fungerer med vilkårlige data. Dette fungerer med et vilkårligt antal elementer i strengen.

Registrer en sammensat type, der består af én text og et integer værdi én gang pr. database. Jeg kalder det ai :

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

Tricket er at danne et array af ai fra hver værdi i kolonnen.

regexp_matches() med mønsteret (\D*)(\d*) og g option returnerer én række for hver kombination af bogstaver og tal. Plus en irrelevant dinglende række med to tomme strenge '{"",""}' Filtrering eller undertrykkelse af det ville blot øge omkostningerne. Aggreger dette i en matrix efter at have erstattet tomme strenge ('' ) med 0 i integer komponent (som '' kan ikke castes til integer ).

NULL værdier sorteres først - eller du er nødt til at bruge dem i særlige tilfælde - eller brug hele shebang i en STRICT funktion som @Craig foreslår.

Postgres 9.4 eller nyere

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<>spil her

Postgres 9.1 (oprindeligt svar)

Testet med PostgreSQL 9.1.5, hvor regexp_replace() havde en lidt anderledes adfærd.

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

Tilføj regexp_replace (left(data, 1), '[1-9]', '0') som første ORDER BY element for at tage sig af førende cifre og tomme strenge.

Hvis specialtegn som {}()"', kan forekomme, bliver du nødt til at undslippe dem i overensstemmelse hermed.
@Craigs forslag om at bruge en ROW expression tager sig af det.

BTW, dette vil ikke køre i sqlfiddle, men det gør det i min db-klynge. JDBC er ikke op til det. sqlfiddle klager:

Metoden org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) er endnu ikke implementeret.

Dette er siden blevet rettet:http://sqlfiddle.com/#!17/fad6e/1



  1. Sådan opretter du en login.sql-fil til SQLcl

  2. Kode til at kalde en funktion i en pakke fra C# og ODP.NET

  3. hvordan tilføjer man brugerdefineret adapter til aktiviteten for at få listen til at blive vist i aktiviteten?

  4. sqlite:hvordan tilføjes samlet tid tt:mm:ss hvor kolonnens datatype er DATETIME?