MySQL - valores ORDER BY dentro de IN ()

107

Espero classificar os itens retornados na consulta a seguir pela ordem em que foram inseridos na função IN () .

ENTRADA:

SELECT id, name FROM mytable WHERE name IN ('B', 'A', 'D', 'E', 'C');

RESULTADO:

|   id   |   name  |
^--------^---------^
|   5    |   B     |
|   6    |   B     |
|   1    |   D     |
|   15   |   E     |
|   17   |   E     |
|   9    |   C     |
|   18   |   C     |

Alguma ideia?

Matt
fonte

Respostas:

231
SELECT id, name
FROM mytable
WHERE name IN ('B', 'A', 'D', 'E', 'C')
ORDER BY FIELD(name, 'B', 'A', 'D', 'E', 'C')

A função FIELD retorna a posição da primeira string na lista de strings restante.

No entanto, é muito melhor em termos de desempenho ter uma coluna indexada que representa sua ordem de classificação e, em seguida, classificar por esta coluna.

Ayman Hourieh
fonte
9
@Vladimir - sim, é específico do MySQL. A questão tem a tag mysql.
Ayman Hourieh
Ótimo, substituto para a função de "decodificação" do Oracle após a troca de banco de dados.
Martin Lyne
7
Cuidado. Qualquer valor de propriedade desconhecido (não na lista) terá precedência sobre os valores conhecidos, ou seja FIELD(letter, 'A', 'C'), a lista retornará primeiro as entradas com a letra B primeiro (assumindo um conjunto de registros com A | B | Cvalores). Para evitar isso, inverta a lista e use DESC, ie FIELD(letter, 'C', 'A') DESC.
Gajus
Como faço para fazer isso no servidor SQL.
user123456
29

Outra opção aqui: http://dev.mysql.com/doc/refman/5.0/en/sorting-rows.html

select * 
from tablename 
order by priority='High' DESC, priority='Medium' DESC, priority='Low" DESC;

Portanto, no seu caso (não testado) seria

SELECT id, name
FROM mytable
WHERE name IN ('B', 'A', 'D', 'E', 'C')
ORDER BY name = 'B', name = 'A', name = 'D', name =  'E', name = 'C';

Dependendo do que você está fazendo, eu achei um pouco peculiar, mas sempre consegui trabalhar depois de brincar um pouco com ele.

joedevon
fonte
Isso pode ser melhor do que usar a função field () como outra resposta sugerida porque o uso de field () impedirá o uso do índice, mas ele tem uma chance de usar um índice usando este método (não tenho certeza de quão bem ele pode usar o índice, no entanto)
ʞɔıu
4

Tente algo como

... ORDER BY (CASE NAME WHEN 'B' THEN 0 WHEN 'A' THEN 1 WHEN ...
Vladimir Dyuzhev
fonte
3

Pode ser que isso possa ajudar alguém (p_CustomerId é passado em SP):

SELECT CompanyAccountId, CompanyName
FROM account
LEFT JOIN customer where CompanyAccountId = customer.AccountId
GROUP BY CompanyAccountId
ORDER BY CASE WHEN CompanyAccountId IN (SELECT AccountId 
                                          FROM customer
                                          WHERE customerid= p_CustomerId) 
                 THEN 0
                 ELSE 1
          END, CompanyName;

Descrição: desejo mostrar a lista de contas. Aqui estou passando um id de cliente em sp. Agora, ele listará os nomes das contas com contas vinculadas a que os clientes são mostrados no topo, seguidos por outras contas em ordem alfabética.

Hun
fonte
2

Você precisa de outra coluna (numérica) em sua tabela, na qual especifica a ordem de classificação. A cláusula IN não funciona dessa maneira.

B - 1
A - 2
D - 3
E - 4
C - 5
Robert Harvey
fonte
2
A ordem desejada pode ser por consulta.
Vladimir Dyuzhev
0

Apenas use

order by INSTR( ',B,C,D,A,' ,  concat(',' , `field`, ',' ) )

evite a situação como

 INSTR('1,2,3,11' ,`field`) 

terminará com linha de resultado não ordenado: 1 e 11 alternantes

PercyQQ
fonte