【问题标题】:Is there a functionality in mysql to order by to specific row?mysql中是否有按特定行排序的功能?
【发布时间】:2019-01-02 05:27:35
【问题描述】:

我有一张桌子,例如学生:

 id | name
 -- |-----
 1  | A
 2  | B
 3  | C
 4  | D
 5  | E
 6  | F
 7  | G
 8  | H`

如何在 mysql 中写一条 sql,以便前 4 个学生按 id 升序排序,其余按 id 降序排序输出应该是这样的

id |  name
---|------
1  | A
2  | B
3  | C
4  | D
8  | H
7  | G
6  | F
5  | E

【问题讨论】:

  • 是的,您可以按子句顺序使用case 语句

标签: mysql sql sorting sql-order-by


【解决方案1】:

您使用的 MySQL 版本早于 8+,这意味着您不能在此处使用分析函数。这是执行此操作的一种方法,使用带有 CASE 表达式的相关子查询:

SELECT t1.id, t1.name
FROM yourTable t1
ORDER BY
    CASE WHEN (SELECT COUNT(*) FROM yourTable t2 WHERE t2.id <= t1.id) <= 4
         THEN 0
         ELSE 1 END,
    CASE WHEN (SELECT COUNT(*) FROM yourTable t2 WHERE t2.id <= t1.id) <= 4
         THEN id
         ELSE -id END;

Demo

我使用相关子查询而不是仅使用id 来计算上面的行号的原因是,您的id 值可能并不总是以1 开头,甚至是连续的。正如id排序,行号始终可以正确定位第一行记录,而id 值本身可能并不总是足够的。

请注意,分析函数使此处的代码更易于阅读。以下是您可以使用 MySQL 8+ 执行的操作:

SELECT t1.id, t1.name
FROM yourTable t1
ORDER BY
    CASE WHEN ROW_NUMBER() OVER (ORDER BY id) <= 4 THEN 0 ELSE 1 END,
    CASE WHEN ROW_NUMBER() OVER (ORDER BY id) <= 4 THEN id ELSE -id END;

【讨论】:

  • 我强烈反对第一种方法。使用相关子查询来枚举行非常昂贵。如果您使用的是 MySQL 8+,那么row_number() 是一个非常好的解决方案。
  • @GordonLinoff 我同意你的看法。如果 OP 长期有这样的要求,那么升级/切换到支持基本分析功能的数据库可能是合适的。
【解决方案2】:

您可以使用相关子查询来计算行的“排名”。排序很简单:

SELECT *, (SELECT COUNT(*) FROM t AS x WHERE id < t.id) AS rn
FROM t
ORDER BY CASE WHEN rn >= 4 THEN -rn END, rn
  • SELECT COUNT(*) FROM t AS x WHERE id &lt; t.id 从 0 开始为每一行分配连续的数字
  • CASE WHEN rn &gt;= 4 THEN -rn END 将 NULL 分配给排名号 0 ... 3,因此需要二次排序。

【讨论】:

    【解决方案3】:

    根据您的样本数据,最简单的方法是:

    order by (case when id <= 4 then 1 else 2 end),
             (case when id <= 4 then id end),
             name desc;
    

    如果你不知道第四个id在哪里,那么:

    select s.*
    from students s cross join
         (select s2.id
          from students s2
          order by s2.id
          limit 3, 1
         ) as s4
    order by (case when s.id <= s4.id then 1 else 2 end),
             (case when s.id <= s4.id then s.id end),
             s.name desc;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 2013-06-12
      • 1970-01-01
      • 2019-02-06
      • 2018-06-26
      • 2012-01-09
      相关资源
      最近更新 更多