【问题标题】:How to define a custom ORDER BY order in mySQL如何在 mySQL 中定义自定义 ORDER BY 顺序
【发布时间】:2023-04-07 10:52:01
【问题描述】:

在 MySQL 中,我如何定义自定义排序顺序。

为了解释我想要什么考虑这张表:

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

在这里,我想返回按语言和升序 ID 排序的所有行,以便首先出现 Language = ENU,然后是 JPN,最后是 DAN。

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

这可能吗?

【问题讨论】:

    标签: mysql


    【解决方案1】:

    MySQL 有一个名为 FIELD() 的便捷函数,非常适合此类任务。

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

    但请注意,

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

    2. 当您的语言列表(或其他排序依据)变得更长时,最好有一个单独的表,其中包含它们的 sortorder 列,并将其连接到您的查询以进行排序。

    【讨论】:

    • 谢谢,这非常适合我只需要按两个值(主要语言,例如 JPN,后备语言,例如 ENU)排序的情况。
    • 伙计,你刚刚用 magento 重写了我 :)
    • 如果您之前有GROUP BY 怎么办?比如我想要的第一个值,出现在最后?
    • 将带有GROUP BY的查询放在子查询中,并在外部查询中排序
    • 不错。我正在编写一个 case order by 子句,但是 field() 更紧凑,更容易重新排序。
    【解决方案2】:

    如果只有这三个值,那么您可以使用a CASE expression

    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 值,您可以有一个单独的表来存储每种 Language 加上一个排序顺序列并链接到该列
    • 这将首先按 ID 排序,结果为 a,b,c,d,e,f
    • 感谢这个完美的作品 - 就像我接受的 Mchl 回答一样,因为它看起来更简单
    【解决方案3】:

    您有几个选项,第一个是将 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 在表定义中,您将其指定为 ENUM 而不是 VARCHAR 等。在内部 MySQL 以特定顺序存储 ENUM 选项并对其进行索引,因此当按 ENUM 列排序时将使用该内部索引而不是字符串值(除非使用 CAST() 将其返回为 VARCHAR)
    • 不应该END DESC,END CASE DESC, 吗?
    • 不。并非所有CASE 都需要END CASE,这取决于上下文。 PROCEDURE 中的 CASE 需要 END CASE ( dev.mysql.com/doc/refman/5.5/en/case.html ) 但是 SELECT 中的 CASE 不需要 END CASE,只需 END (dev.mysql.com/doc/refman/5.7/en/… ) - 在这种情况下,它是一个控制流函数。
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 2021-12-06
      • 2014-01-17
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 2011-05-04
      • 1970-01-01
      • 2017-08-02
      • 1970-01-01
      相关资源
      最近更新 更多