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

Ordina la stringa varchar come numerica

È assolutamente possibile.

ORDER BY varchar_column::int

Assicurati di avere valori interi validi nel tuo varchar colonna per ogni voce o ottieni un'eccezione invalid input syntax for integer: ... . (Lo spazio bianco iniziale e finale va bene:verrà tagliato automaticamente.)

Se è così, però, perché non convertire la colonna in integer iniziare con? Più piccolo, più veloce, più pulito, più semplice.

Come evitare le eccezioni?

Per rimuovere i caratteri non numerici prima del cast e quindi evitare possibili eccezioni:

ORDER BY NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '')::int
  • Il regexp_replace() l'espressione rimuove efficacemente tutte le non cifre, quindi rimangono solo le cifre o una stringa vuota. (Vedi sotto.)

  • \D è un'abbreviazione per la classe di caratteri [^[:digit:]] , ovvero tutte le non cifre ([^0-9] ).
    Nelle vecchie versioni di Postgres con l'impostazione obsoleta standard_conforming_strings = off , devi usare la sintassi della stringa di escape Posix E'\\D' per evitare la barra rovesciata \ . Questo era l'impostazione predefinita in Postgres 8.3, quindi ti servirà per la tua versione obsoleta.

  • Il 4° parametro g sta per "globalmente" , indicando di sostituire tutti occorrenze, non solo la prima.

  • puoi vuoi consentire un trattino iniziale (- ) per i numeri negativi.

  • Se la stringa non ha alcuna cifra, il risultato è una stringa vuota che non è valida per un cast a integer . Converti stringhe vuote in NULL con NULLIF . (Potresti considerare 0 invece.)

Il risultato è garantito per essere valido. Questa procedura è per un cast a integer come richiesto nel corpo della domanda, non per numeric come dice il titolo.

Come renderlo veloce?

Un modo è un indice su un'espressione.

CREATE INDEX tbl_varchar_col2int_idx ON tbl
(cast(NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '') AS integer));

Quindi usa la stessa espressione in ORDER BY clausola:

ORDER BY
cast(NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '') AS integer)

Prova con EXPLAIN ANALYZE se l'indice funzionale viene effettivamente utilizzato.