Как определить собственный заказ ORDER BY в mySQL

148

Как в MySQL определить собственный порядок сортировки.

Чтобы попытаться объяснить, что я хочу, рассмотрим эту таблицу:

ID  Language    Text
0   ENU         a
0   JPN         b
0   DAN         c       
1   ENU         d
1   JPN         e
1   DAN         f
2   etc...

здесь я хочу вернуть все строки, отсортированные по языку и идентификатору по возрастанию, чтобы сначала было Language = ENU, затем JPN и, наконец, DAN.

Результат должен быть: a, d, b, e, c, f и т. Д.

Это вообще возможно?

Muleskinner
источник

Ответы:

284

В MySQL есть удобная функция, FIELD()которая отлично подходит для таких задач.

ORDER BY FIELD(Language,'ENU','JPN','DAN'), ID

Однако обратите внимание, что

  1. Это делает ваш SQL менее переносимым, так как другие СУБД могут не иметь такой функции.

  2. Когда ваш список языков (или других значений для сортировки) становится намного длиннее, лучше иметь для них отдельную таблицу со столбцом sortorder и присоединять ее к вашим запросам для упорядочивания.

Mchl
источник
3
Спасибо, это идеально подходит для моей ситуации, когда мне просто нужно упорядочить по двум значениям (основной язык, например JPN, и резервный язык, например ENU).
Muleskinner
5
Чувак, ты только что сохранил для меня переписывание в magento :)
Эрик Саймоник
1
Что делать, если у вас есть GROUP BYраньше? Например, первое значение, которое я хочу, отображается в конце?
Pathros
Поместите запрос с помощью GROUP BYв подзапрос и упорядочите его во внешнем запросе
Mchl
1
Работайте как шарм :)
Брейн
55

Если только эти три значения, то вы можете использовать в CASEвыражение :

ORDER BY `ID`,
         CASE `Language`
         WHEN 'ENU' THEN 1
         WHEN 'JPN' THEN 2
         WHEN 'DAN' THEN 3
         END

(Если могут быть другие значения, вы можете добавить некоторую дополнительную логику, чтобы упорядочить порядок; например, вы можете добавить ELSE 4к этому CASEвыражению, а затем упорядочить его Languageкак третий критерий упорядочения:

ORDER BY `ID`,
         CASE `Language`
         WHEN 'ENU' THEN 1
         WHEN 'JPN' THEN 2
         WHEN 'DAN' THEN 3
         ELSE 4
         END,
         `Language`

)

руах
источник
1
И если есть много значений Language, у вас может быть отдельная таблица, в которой хранится каждый язык, плюс столбец порядка сортировки и ссылка на него
kaj
1
Сначала это будет упорядочено по идентификатору, в результате чего получится a, b, c, d, e, f
piotrm
Спасибо, это отлично работает - как и ответ Mchl, который я принял, поскольку он выглядит проще
Muleskinner
19

У вас есть несколько вариантов, во-первых, изменить Language на ENUM (при условии, что это возможно, и вы ожидаете только несколько вариантов)

Если вы укажете это как, ENUM('ENU','JPN','DAN')то ORDER Language ASCбудет заказывать в указанном вами порядке.

Второй будет связан с чем-то, т.е.

SELECT * FROM table
ORDER BY CASE Language
    WHEN 'ENU' THEN 3
    WHEN 'JPN' THEN 2
    WHEN 'DAN' THEN 1
    ELSE 0
END DESC, ID ASC

С точки зрения производительности метод ENUM будет возвращать более быстрые результаты, но доставит больше хлопот, если вам нужно добавить больше языков. Третий вариант - добавить таблицу нормализации для языков, однако в данном случае это может оказаться излишним.

Саймон на портале моей школы
источник
Где именно вы печатаете ENUM('ENU','JPN','DAN')?
Pathros
1
@pathros в определении таблицы, вы указываете его как ENUM вместо VARCHAR и т. д. Внутренне MySQL хранит параметры ENUM в определенном порядке и индексирует их, поэтому при упорядочивании по столбцу ENUM он будет использовать этот внутренний индекс вместо строковые значения (если только CAST () не используется для возврата к VARCHAR)
Саймон на портале My School Portal
Не должно END DESC,быть END CASE DESC,?
Istiaque Ahmed
Неа. Не все CASEнужно END CASE, это зависит от контекста. CASEв ПРОЦЕДУРЕ требуется END CASE( dev.mysql.com/doc/refman/5.5/en/case.html ), однако CASEв SELECT не требуется END CASE, просто END( dev.mysql.com/doc/refman/5.7/en/… ) - в этом контекст это функция потока управления.
Саймон на портале моей школы
2

Для структуры Yii2 мы можем добиться следующего:

Project::find()
->orderBy([new Expression('FIELD(pid_is_t_m,2,0,1)'),'task_last_work'=> SORT_ASC])
->all();
Прахлад
источник