sql >> Database >  >> RDS >> PostgreSQL

Gehumaniseerde of natuurlijke nummersortering van gemengde woord-en-nummerreeksen

Voortbouwend op uw testgegevens, maar dit werkt met willekeurige gegevens. Dit werkt met een willekeurig aantal elementen in de string.

Registreer een samengesteld type bestaande uit één text en één integer waarde eenmaal per database. Ik noem het ai :

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

De truc is om een ​​array te vormen van ai van elke waarde in de kolom.

regexp_matches() met het patroon (\D*)(\d*) en de g optie retourneert één rij voor elke combinatie van letters en cijfers. Plus een irrelevante bungelende rij met twee lege strings '{"",""}' Het filteren of onderdrukken zou alleen maar meer kosten opleveren. Voeg dit samen tot een array, na het vervangen van lege strings ('' ) met 0 in het integer component (als '' kan niet worden gecast naar integer ).

NULL waarden sorteer eerst - of je moet ze speciaal maken - of gebruik de hele shebang in een STRICT functioneren zoals @Craig voorstelt.

Postgres 9.4 of hoger

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<>viool hier

Postgres 9.1 (oorspronkelijk antwoord)

Getest met PostgreSQL 9.1.5, waarbij regexp_replace() had een iets ander gedrag.

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

Voeg regexp_replace (left(data, 1), '[1-9]', '0') toe als eerste ORDER BY item om voorloopcijfers en lege tekenreeksen op te lossen.

Als speciale tekens zoals {}()"', kunnen voorkomen, moet u dienovereenkomstig ontsnappen.
Suggestie van @Craig om een ​​ROW te gebruiken expressie zorgt daarvoor.

BTW, dit wordt niet uitgevoerd in sqlfiddle, maar wel in mijn db-cluster. JDBC kan het niet aan. sqlfiddle klaagt:

Methode org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) is nog niet geïmplementeerd.

Dit is sindsdien opgelost:http://sqlfiddle.com/#!17/fad6e/1



  1. MySQL auto-increment kolom springt met 10 waarom?

  2. Rollen gebruiken die nieuw zijn in MySQL 8

  3. Een tabel maken in MySQL

  4. Hoe echo ik een Resource-id #6 van een MySql-antwoord in PHP?