2013-03-15 9 views
13

Sono nuovo di postrge e desidero ordinare le colonne di tipo varchar. vuole spiegare il problema con la con la sottostante esempio:Caso alfanumerico ordinamento in-sensitive in postgres

nome della tabella: testsorting ordinamento sensibile

order  name 
    1   b 
    2   B 
    3   a 
    4   a1 
    5   a11 
    6   a2 
    7   a20 
    8   A 
    9   a19 

caso (che è di default in Postgres) dà:

select name from testsorting order by name; 

    A 
    B 
    a 
    a1 
    a11 
    a19 
    a2 
    a20 
    b 

caso in- l'ordinamento sensibile fornisce:

selezionare il nome dall'ordine di testorting da UPPER (nome);

 A 
     a 
     a1 
     a11 
     a19 
     a2 
     a20 
     B 
     b 

Come posso fare caso alfanumerico sensibili ordinamento in Postgres per ottenere sotto ordine:

  a 
      A 
      a1 
      a2 
      a11 
      a19 
      a20 
      b 
      B 

I wont importa l'ordine per il capitale o minuscole, ma l'ordine dovrebbe essere " aAbB "o" AaBb "e non dovrebbe essere" ABab "

Si prega di suggerire se si dispone di una soluzione a questo in postgres.

risposta

5

My PostgreSQL ordina nel modo desiderato. Il modo in cui PostgreSQL confronta le stringhe è determinato dalla locale e dalle regole di confronto. Quando si crea il database utilizzando createdb, è disponibile l'opzione -l per impostare la locale. Inoltre è possibile verificare come è configurato nel proprio ambiente utilizzando psql -l:

[[email protected]]$ psql -l 
List of databases 
Name | Owner | Encoding | Collate | Ctype | Access privileges 
---------+----------+----------+------------+------------+----------------------- 
mn_test | postgres | UTF8  | pl_PL.UTF8 | pl_PL.UTF8 | 

Come si vede il mio database utilizza le regole di confronto polacco.

Se è stato creato database utilizzando altre regole di confronto quindi è possibile utilizzare altri collazione nella query Proprio come:

SELECT * FROM sort_test ORDER BY name COLLATE "C"; 
SELECT * FROM sort_test ORDER BY name COLLATE "default"; 
SELECT * FROM sort_test ORDER BY name COLLATE "pl_PL"; 

Si possono elencare le regole di confronto disponibili da:

SELECT * FROM pg_collation; 

CURA:

Oh, mi sono perso che 'a11' deve essere prima di 'a2'.

Non penso che le regole di confronto standard possano risolvere l'ordinamento alfanumerico. Per tale ordinamento dovrai dividere le stringhe in parti come nella risposta di Clodoaldo Neto. Un'altra opzione che è utile se si deve spesso ordinare in questo modo è separare il campo del nome in due colonne.È possibile creare trigger su INSERT e UPDATE che ha diviso name in name_1 e name_2 e poi:

SELECT name FROM sort_test ORDER BY name_1 COLLATE "en_EN", name_2; 

(ho cambiato le regole di confronto dal polacco in inglese, si dovrebbe usare il tuo collazione nativo per ordinare lettere come AACC ecc)

+0

Grazie Michal. Ho controllato psql -l ma non mi mostrava la locale configurata. Utilizzando COLLATE "pl_PL" in SELEZIONA ha funzionato e ordinato la lista in caso in-sensibile tuttavia il problema ancora con l'alfanumerico e "a2" è elencato dopo "a11" e "a19". vuoi dire che l'utilizzo di una corretta COLLATE risolverà l'ordinamento alfanumerico? – akhi

+0

Vedere la mia risposta a cura –

4

Se il nome è sempre nel formato 1 alpha followed by n numerics poi:

select name 
from testsorting 
order by 
    upper(left(name, 1)), 
    (substring(name from 2) || '0')::integer 
+0

sto ottenendo ERRORE: la sintassi di input non valido per intero: "" con questo. Devo controllare la collazione ?? Se rimuovo :: intero alla fine, ho un output che non è esattamente ordinato. a11 e a19 elencati prima di a2, che è sbagliato (A, a, a1, a11, a19, a2, a20, B, b). L'ordine corretto dovrebbe essere A, a, a1, a2, a11, a19, a20, B, b. – akhi

+0

@Akhilesh corretto. –

+0

Grazie Clodoaldo. Ho ricevuto questo errore a causa del valore null, quindi è necessario un sovraccarico aggiuntivo per gestire il valore nullo nell'approccio suggerito. eventuali commenti? – akhi

-1

sono d'accordo con la risposta di Clodoaldo Neto, ma anche non dimenticare di aggiungere l'indice

CREATE INDEX testsorting_name on testsorting(upper(left(name,1)), substring(name from 2)::integer) 
+0

Questo è l'indice, non l'ordine di. Non ordinerà la tua lista, la risposta di Clodoaldo Neto sarà. Questo renderà l'ordinamento efficiente. –

+0

Questo indice probabilmente non verrà utilizzato per l'ordinamento. Solo un indice univoco viene utilizzato per l'ordinamento per quanto posso vederlo qui con 9.3. Sarei felice di essere smentito, anche se ... – Risadinha

+0

qualsiasi indice B-tree può essere utilizzato per una specie, a prescindere se è unico nel suo genere: http://www.postgresql.org/docs/9.3/static/indexes- ordering.html. Ovviamente dipende da un indice esistente che riflette la query specifica che viene fatta. –

0

risposta fortemente ispirati da this one.
Utilizzando una funzione sarà più facile mantenerlo pulito se necessario su diverse query.

CREATE OR REPLACE FUNCTION alphanum(str anyelement) 
    RETURNS anyelement AS $$ 
BEGIN 
    RETURN (SUBSTRING(str, '^[^0-9]*'), 
     COALESCE(SUBSTRING(str, '[0-9]+')::INT, -1) + 2000000); 
END; 
$$ LANGUAGE plpgsql IMMUTABLE; 

allora si potrebbe utilizzare in questo modo:

SELECT name FROM testsorting ORDER BY alphanum(name); 

prova:

WITH x(name) AS (VALUES ('b'), ('B'), ('a'), ('a1'), 
    ('a11'), ('a2'), ('a20'), ('A'), ('a19')) 
SELECT name, alphanum(name) FROM x ORDER BY alphanum(name); 

name | alphanum 
------+------------- 
a | (a,1999999) 
A | (A,1999999) 
a1 | (a,2000001) 
a2 | (a,2000002) 
a11 | (a,2000011) 
a19 | (a,2000019) 
a20 | (a,2000020) 
b | (b,1999999) 
B | (B,1999999) 
Problemi correlati