MySQL - значения ORDER BY в IN ()

108

Я надеюсь отсортировать элементы, возвращаемые в следующем запросе, по порядку их ввода в функцию IN () .

ВХОД:

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

ВЫВОД:

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

Любые идеи?

Мэтт
источник

Ответы:

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

Функция FIELD возвращает позицию первой строки в оставшемся списке строк.

Однако с точки зрения производительности гораздо лучше иметь индексированный столбец, представляющий ваш порядок сортировки, а затем сортировать по этому столбцу.

Айман Хурье
источник
9
@Vladimir - да, это специфично для MySQL. В вопросе есть тег mysql.
Ayman Hourieh 06
Отлично, замена функции Oracle "декодировать" после переключения БД.
Мартин Лайн
7
Осторожный. Любое неизвестное значение свойства (не указанное в списке) будет иметь приоритет перед известными значениями, т. Е. FIELD(letter, 'A', 'C')Список сначала будет возвращать записи с буквой B (при условии, что набор записей со A | B | Cзначениями). Чтобы избежать этого, инвертировать список и использовать DESC, то есть FIELD(letter, 'C', 'A') DESC.
Gajus
Как мне добиться этого на SQL-сервере.
user123456
29

Другой вариант отсюда: 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;

Итак, в вашем случае (непроверенный) будет

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';

В зависимости от того, что вы делаете, я нахожу это немного странным, но всегда заставлял его работать после того, как немного поигрался с ним.

Джодевон
источник
Это может быть лучше, чем использование функции field () в качестве другого предлагаемого ответа, потому что использование field () предотвратит использование индекса, но у него есть возможность использовать индекс с помощью этого метода (хотя не уверен, насколько хорошо он может использовать индекс)
ıu 06
4

Попробуйте что-нибудь вроде

... ORDER BY (CASE NAME WHEN 'B' THEN 0 WHEN 'A' THEN 1 WHEN ...
Владимир Дюжев
источник
3

Может быть, это кому-то поможет (p_CustomerId передается в 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;

Описание: Я хочу показать список аккаунтов. Здесь я передаю идентификатор клиента в sp. Теперь он будет перечислять имена учетных записей с учетными записями, связанными с которыми клиенты показаны вверху, за которыми следуют другие учетные записи в алфавитном порядке.

Гунн
источник
2

Вам нужен другой столбец (числовой) в вашей таблице, в котором вы указываете порядок сортировки. Предложение IN таким образом не работает.

B - 1
A - 2
D - 3
E - 4
C - 5
Роберт Харви
источник
2
Желаемый порядок может быть по запросу.
Владимир Дюжев
0

просто используйте

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

Избегайте такой ситуации, как

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

закончится неупорядоченной строкой результата: 1 и 11 альтернант

PercyQQ
источник