Stringa dell'ordine SQL come numero


137

Ho dei numeri salvati VARCHARsu un database MySQL. Non posso farli a INTcausa di altre circostanze dipendenti.

Li sta prendendo come personaggio, non come numero durante l'ordinamento.

Nel database che ho

1 2 3 4 5 6 7 8 9 10...

Sulla mia pagina mostra un elenco ordinato come questo:

1 10 2 3 4 5 6 7 8 9

Come posso farlo apparire ordinato in base ai numeri in ordine crescente?


5
Sicuramente avresti dovuto archiviare i dati come numero, anziché come stringa.
Oded,

@Oded È possibile disporre di alcuni dati arbitrari (ad es. Impostazioni), che si desidera ordinare in base al suo valore numerico solo in casi molto speciali.
Glutexo,

articolo molto interessante - è per MSSQL ma dovrebbe essere relativamente simile per MySQL: essentialsql.com/use-sql-server-to-sort-alphanumeric-values
AquaAlex

Risposte:


256

Se possibile, è necessario modificare il tipo di dati della colonna in un numero se si memorizzano comunque solo numeri.

Se non riesci a farlo, esegui il cast del valore della colonna in modo integer esplicito con

select col from yourtable
order by cast(col as unsigned)

o implicitamente per esempio con un'operazione matematica che forza una conversione in numero

select col from yourtable
order by col + 0

BTW MySQL converte le stringhe da sinistra a destra. Esempi:

string value  |  integer value after conversion
--------------+--------------------------------
'1'           |  1
'ABC'         |  0   /* the string does not contain a number, so the result is 0 */
'123miles'    |  123 
'$123'        |  0   /* the left side of the string does not start with a number */

3
ordina per col * 1 funziona perfettamente. Qual è la magia dietro questo? Spiacente, non sono professionale, quindi questa potrebbe essere una domanda sciocca, ma come * 1 lo fa cambiare in numero?
Jamol

12
MySQL converte automaticamente la stringa in un numero per effettuare la moltiplicazione con1
juergen d

1
La prima opzione è la più appropriata, la seconda ha un passaggio in più, ma funziona comunque.
Manatax,

5
e se hai stringa e numero misti e vuoi che siano ordinati, usa "ordina per col * 1, col"
Hayden Thring,

1
@superphonic: il risultato sarà decimal.
juergen d

70

Un altro modo, senza usare un solo cast.

(Per le persone che usano JPA 2.0, dove non è consentito il casting)

select col from yourtable
order by length(col),col

EDIT: funziona solo per numeri interi positivi


9
questo è buono, ha funzionato con la colonna che contiene anche int e stringa
Sruit A.Suk

1
Questo non funzionerà in tutti i casi. Dalla parte superiore della testa, i casi che non funzionano sono miscele di numeri interi con; numeri negativi, numeri con zeri iniziali, numeri con frazioni e parole e numeri combinati.
WonderWorker,

3
ottima soluzione senza alcun tipo di casting e giocoleria in giro, +1
Maksim Luzik

non sembra funzionare a prima vista, ma ha funzionato! Grazie!
try2fly.b4ucry


17

La colonna con cui sto ordinando ha qualsiasi combinazione di alfa e numerica, quindi ho usato i suggerimenti in questo post come punto di partenza e ne sono uscito.

DECLARE @tmp TABLE (ID VARCHAR(50));
INSERT INTO @tmp VALUES ('XYZ300');
INSERT INTO @tmp VALUES ('XYZ1002');
INSERT INTO @tmp VALUES ('106');
INSERT INTO @tmp VALUES ('206');
INSERT INTO @tmp VALUES ('1002');
INSERT INTO @tmp VALUES ('J206');
INSERT INTO @tmp VALUES ('J1002');

SELECT ID, (CASE WHEN ISNUMERIC(ID) = 1 THEN 0 ELSE 1 END) IsNum
FROM @tmp
ORDER BY IsNum, LEN(ID), ID;

risultati

ID
------------------------
106
206
1002
J206
J1002
XYZ300
XYZ1002

Spero che questo ti aiuti


Puoi semplicemente usare 1 - ISNUMERIC(ID)invece di (CASE WHEN ISNUMERIC(ID) = 1 THEN 0 ELSE 1 END)cambiare da 0 a 1 e viceversa.
S. Serpooshan il

7

Questo funziona per me.

select * from tablename
order by cast(columnname as int) asc

puoi spiegare perché?
Slavik,

la risposta più semplice, che fa esattamente ciò che è necessario, getta la stringa su un int, quindi ordina da quell'int in ordine crescente, niente roba funky :)
denford mutseriwa

4

Un altro modo per convertire.

Se si dispone di un campo stringa, è possibile trasformarlo o la sua parte numerica nel modo seguente: aggiungere zeri iniziali per rendere tutte le stringhe intere di uguale lunghezza.

ORDER BY CONCAT( REPEAT(  "0", 18 - LENGTH( stringfield ) ) , stringfield ) 

oppure ordina per parte di un campo qualcosa come "tensymbols13", "tensymbols1222" ecc.

ORDER BY CONCAT( REPEAT(  "0", 18 - LENGTH( LEFT( stringfield , 10 ) ) ) , LEFT( stringfield , 10 ) ) 

2

Stavo cercando anche un campo di smistamento con prefisso lettera. Ecco cosa ho scoperto la soluzione. Questo potrebbe aiutare chi sta cercando la stessa soluzione.

Valori di campo:

FL01,FL02,FL03,FL04,FL05,...FL100,...FL123456789

select SUBSTRING(field,3,9) as field from table order by SUBSTRING(field,3,10)*1 desc

SUBSTRING(field,3,9) ho messo 9 perché 9 è abbastanza per me per contenere un massimo di 9 cifre valori interi.

Quindi il risultato sarà 123456789 123456788 123456787 ... 100 99 ... 2 1


2

Questo gestirà numeri negativi, frazioni, stringhe, tutto:

ORDER BY ISNUMERIC(col) DESC, Try_Parse(col AS decimal(10,2)), col;

2

Potrebbe aiutare chi cerca la stessa soluzione.

select * from tablename ORDER BY ABS(column_name)

0

Se si utilizza AdonisJS e si hanno ID misti come ABC-202, ABC-201 ..., è possibile combinare query non elaborate con Query Builder e implementare la soluzione sopra ( https://stackoverflow.com/a/25061144/4040835 ) come segue:

const sortField =
  'membership_id'
const sortDirection =
  'asc'
const subquery = UserProfile.query()
  .select(
    'user_profiles.id',
    'user_profiles.user_id',
    'user_profiles.membership_id',
    'user_profiles.first_name',
    'user_profiles.middle_name',
    'user_profiles.last_name',
    'user_profiles.mobile_number',
    'countries.citizenship',
    'states.name as state_of_origin',
    'user_profiles.gender',
    'user_profiles.created_at',
    'user_profiles.updated_at'
  )
  .leftJoin(
    'users',
    'user_profiles.user_id',
    'users.id'
  )
  .leftJoin(
    'countries',
    'user_profiles.nationality',
    'countries.id'
  )
  .leftJoin(
    'states',
    'user_profiles.state_of_origin',
    'states.id'
  )
  .orderByRaw(
    `SUBSTRING(:sortField:,3,15)*1 ${sortDirection}`,
    {
      sortField: sortField,
    }
  )
  .paginate(
    page,
    per_page
  )

NOTE: In questa linea: SUBSTRING(:sortField:,3,15)*1 ${sortDirection},

  1. '3' indica il numero indice dell'ultimo carattere non numerico prima delle cifre. Se il tuo ID misto è "ABC-123", il tuo numero di indice sarà 4.
  2. '15' viene utilizzato per catturare il maggior numero possibile di cifre dopo il trattino.
  3. '1' esegue un'operazione matematica sulla sottostringa che lancia effettivamente la sottostringa su un numero.

Rif 1: Puoi leggere di più sui binding dei parametri nelle query non elaborate qui: https://knexjs.org/#Raw-Bindings Rif 2: Adonis Raw Query: https://adonisjs.com/docs/4.1/query-builder# _raw_queries


-3

Modifica il tuo campo in INT anziché VARCHAR.

Non posso renderli INT a causa di altre circostanze dipendenti.

Quindi correggere prima le circostanze dipendenti. Altrimenti stai risolvendo il vero problema di fondo. L'uso di un cast MySQL è un'opzione, ma sta mascherando il tuo cattivo schema che dovrebbe essere risolto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.