Sequência de pedidos SQL como número


137

Tenho números salvos como VARCHARum banco de dados MySQL. Não posso fazê-los INTdevido a outras circunstâncias dependentes.

Ele está tomando como caractere e não como número durante a classificação.

No banco de dados eu tenho

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

Na minha página, mostra a lista ordenada como esta:

1 10 2 3 4 5 6 7 8 9

Como posso fazer com que pareça ordenado por números ascendentes?


5
Certamente você deveria ter armazenado os dados como um número, em vez de uma string.
Oded

@Oded Você pode ter alguns dados arbitrários (por exemplo, configurações), que você deseja ordenar por seu valor numérico apenas em casos muito especiais.
Glutexo 13/02/19

artigo muito interessante - é para MSSQL, mas deve ser relativamente semelhante para MySQL: essentialsql.com/use-sql-server-to-sort-alphanumeric-values
AquaAlex

Respostas:


256

Se possível, você deve alterar o tipo de dados da coluna para um número, se você só armazenar números de qualquer maneira.

Se você não puder fazer isso, converta o valor da coluna para um integer explicitamente com

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

ou implicitamente, por exemplo, com uma operação matemática que força uma conversão para número

select col from yourtable
order by col + 0

BTW MySQL converte strings da esquerda para a direita. Exemplos:

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
ordenar por col * 1 funciona perfeitamente. Qual é a mágica por trás disso? Desculpe, eu não sou profissional, então isso pode ser uma pergunta boba, mas como * 1 faz com que mude para número?
Jamol

12
MySQL converte automaticamente a string para um número para fazer a multiplicação1
juergen d

1
A primeira opção é a mais apropriada, a segunda possui uma etapa extra, mas funciona de maneira alguma.
Manatax

5
e se você tem cadeia mista e número e quero que eles tanto classificadas, use "a fim de col * 1, col"
Hayden Thring

1
@ superphonic: O resultado será decimal.
juergen d

70

Outra maneira, sem usar um único elenco.

(Para pessoas que usam o JPA 2.0, onde nenhuma transmissão é permitida)

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

EDIT: funciona apenas para números inteiros positivos


9
este é um bom, isso é trabalhado com coluna que também contêm tanto int e corda
Sruit A.Suk

1
Isso não funcionará em todos os casos. Em primeiro lugar, os casos que não funcionam são misturas de números inteiros; números negativos, números com zeros à esquerda, números com frações e palavras e números combinados.
precisa

3
grande solução sem quaisquer fundição e malabarismo tipos ao redor, +1
Maksim Luzik

não parecia funcionar à primeira vista, mas funcionou! Obrigado!
try2fly.b4ucry


17

A coluna com a qual estou classificando tem qualquer combinação de alfa e numérica, por isso usei as sugestões nesta postagem como ponto de partida e criei isso.

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;

Resultados

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

Espero que isto ajude


Você pode simplesmente usar em 1 - ISNUMERIC(ID)vez de (CASE WHEN ISNUMERIC(ID) = 1 THEN 0 ELSE 1 END)mudar de 0 para 1 e vice-versa.
S.Serpooshan

7

Isso funciona para mim.

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

você pode explicar o porquê?
Slavik

a resposta simples maioria, que faz exatamente o que é necessário, lançar a string para um int, então a ordem por que int em ordem crescente, nenhum material funky :)
mutseriwa Denford

4

Outra maneira de converter.

Se você tiver um campo de string, poderá transformá-lo ou sua parte numérica da seguinte maneira: adicione zeros à esquerda para fazer com que todas as strings inteiras tenham o mesmo comprimento.

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

ou encomende por parte de um campo algo como 'tensymbols13', 'tensymbols1222' etc.

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

2

Eu estava procurando também um campo de classificação com prefixo de letra. Aqui está o que eu descobri a solução. Isso pode ajudar quem está procurando a mesma solução.

Valores do 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) Eu coloquei 9 porque 9 é o suficiente para eu manter no máximo 9 dígitos com valores inteiros.

Portanto, o resultado será 123456789 123456788 123456787 ... 100 99 ... 2 1


2

Isso manipulará números negativos, frações, string, tudo:

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

2

Pode ajudar quem está procurando a mesma solução.

select * from tablename ORDER BY ABS(column_name)

0

Se você estiver usando o AdonisJS e tiver IDs mistos como ABC-202, ABC-201 ..., poderá combinar consultas brutas com o Query Builder e implementar a solução acima ( https://stackoverflow.com/a/25061144/4040835 ) do seguinte modo:

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
  )

NOTAS: Nesta linha: SUBSTRING(:sortField:,3,15)*1 ${sortDirection},

  1. '3' representa o número do índice do último caractere não numérico antes dos dígitos. Se seu ID misto for "ABC-123", seu número de índice será 4.
  2. '15' é usado para capturar o maior número possível de dígitos após o hífen.
  3. '1' executa uma operação matemática na substring que efetivamente lança a substring em um número.

Ref 1: Você pode ler mais sobre ligações de parâmetros em consultas brutas aqui: https://knexjs.org/#Raw-Bindings Ref 2: consultas brutas do Adonis: https://adonisjs.com/docs/4.1/query-builder# _raw_queries


-3

Altere seu campo para INT em vez de VARCHAR.

Não posso torná-los INT devido a outras circunstâncias.

Em seguida, corrija as circunstâncias dependentes primeiro. Caso contrário, você está solucionando o problema subjacente real. Usar um MySQL CAST é uma opção, mas está mascarando seu esquema inválido, que deve ser corrigido.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.