sql >> Databasteknik >  >> RDS >> PostgreSQL

Humaniserad eller naturlig nummersortering av blandade ord-och-nummersträngar

Bygger på dina testdata, men det här fungerar med godtyckliga data. Detta fungerar med valfritt antal element i strängen.

Registrera en sammansatt typ som består av en text och ett integer värde en gång per databas. Jag kallar det ai :

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

Tricket är att bilda en array av ai från varje värde i kolumnen.

regexp_matches() med mönstret (\D*)(\d*) och g alternativet returnerar en rad för varje kombination av bokstäver och siffror. Plus en irrelevant dinglande rad med två tomma strängar '{"",""}' Att filtrera eller undertrycka det skulle bara öka kostnaden. Aggregera detta till en array efter att ha ersatt tomma strängar ('' ) med 0 i integer komponent (som '' kan inte casta till integer ).

NULL värden sorteras först - eller så måste du använda specialfall för dem - eller använd hela shebang i en STRICT fungerar som @Craig föreslår.

Postgres 9.4 eller senare

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<>spela här

Postgres 9.1 (ursprungligt svar)

Testad med PostgreSQL 9.1.5, där regexp_replace() hade ett lite annorlunda beteende.

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

Lägg till regexp_replace (left(data, 1), '[1-9]', '0') som första ORDER BY objekt för att ta hand om inledande siffror och tomma strängar.

Om specialtecken som {}()"', kan inträffa, måste du undkomma dem i enlighet med detta.
@Craigs förslag att använda en ROW expression tar hand om det.

BTW, detta kommer inte att köras i sqlfiddle, men det gör det i mitt db-kluster. JDBC klarar inte av det. sqlfiddle klagar:

Metoden org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) är ännu inte implementerad.

Detta har sedan åtgärdats:http://sqlfiddle.com/#!17/fad6e/1



  1. mysql_fetch_assoc():det angivna argumentet är inte en giltig MySQL-resultatresurs i php

  2. Använda Metadata Discovery Wizard

  3. En översikt över den nya DBaaS från MariaDB - SkySQL

  4. Docker - Hur kan man köra kommandot psql i postgres-behållaren?