如何在 mySQL 中定义自定义 ORDERBY 顺序

在 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 和升序 ID 排序的行,这样 Language = ENU 排在第一位,然后是 JPN,最后是 DAN。

结果应该是: a,d,b,e,c,f 等。

这有可能吗?

115031 次浏览

如果只有这三个值,那么可以使用 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`

)

您现在有两个选项,第一个选项是将 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 方法将返回更快的结果,但是如果需要添加更多语言,则会更麻烦。第三种选择是为语言添加一个规范化表,但是在这个实例中这可能有点过了。

MySQL 有一个称为 FIELD()的方便函数,非常适合这类任务。

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

不过请注意

  1. 它使 SQL 的可移植性降低,因为其他 DBMS 可能没有这样的功能

  2. 当您的语言列表(或其他需要进行排序的值)越来越长时,最好使用一个单独的表,其中包含这些语言的 sortorder 列,并将其连接到用于排序的查询中。

对于 Yii2框架,我们可以通过以下方式实现

Project::find()
->orderBy([
new Expression('FIELD(pid_is_t_m,2,0,1)'),
'task_last_work'=> SORT_ASC
])->all();