【问题标题】:order by clause in MysqlMysql中的order by子句
【发布时间】:2017-12-07 07:20:59
【问题描述】:

我正在写一个sql来获取一个数字列表的媒介(假设列表的长度是奇数)

set @r=0; select S.num from (select num, case when num is not NULL then (@r:=@r+1) end as rowIndex from T1 order by num) S where rowIndex = ceil(@r/2) 这个查询有效,但是,我对我的子查询感到困惑。我的问题如下:如果我只是输入 select num, case when num is not NULL then (@r:=@r+1) end as rowIndex from T1 我将有 2 列,第一列是原始顺序中的原始数字列表,例如 10,1,3,11,5,4,19...,第二列是行索引,1,2 ,3,4,.... 请注意,我想要的是首先按升序对原始列表进行排序,然后为每一行指定其行索引。

我一开始以为 select num, case when num is not NULL then (@r:=@r+1) end as rowIndex from T1 order by num 将生成一个表,其中第一列是我的原始列表的排序版本,但第二列是索引集 [1,2,3,...] 的重新排列。因为我认为查询的顺序是:首先按照select num, case when num is not NULL then (@r:=@r+1) end as rowIndex from T1的建议创建一个表,然后按num列对该表进行排序,因此,当num列排序时,rowIndex列应该没有不再是 [1,2,3,...]。

但实际上,它似乎首先对num 列进行排序,然后添加行索引。换句话说,我发现无论我是否添加order by num,第二列总是一个不错的行索引[1,2,3,4,...]。为什么?

【问题讨论】:

  • 你能添加一个表格数据示例吗,因为现在很难理解你在说什么
  • @NorbertvanNobelen 抱歉,我正要这样做,@Used_By_Already 在下面的答案中做了一个表格。但是我仍然对Mysql中的这个order by子句感到困惑

标签: mysql sorting


【解决方案1】:

派生表(子查询)对您的num 列进行排序,并根据该顺序为每一行提供一个索引号。然后,外部查询重新使用 @r 的计算值来到达该有序序列的中点(中值)。

CREATE TABLE mytable(
   num NUMERIC(6,2)
);
INSERT INTO mytable(num) VALUES (12.4);
INSERT INTO mytable(num) VALUES (134.9);
INSERT INTO mytable(num) VALUES (45.12);
INSERT INTO mytable(num) VALUES (876.78);
INSERT INTO mytable(num) VALUES (212.8);
INSERT INTO mytable(num) VALUES (578.9);
set @r=0;
select num, case when num is not NULL then (@r:=@r+1) end as rowIndex
from mytable T1
order by num;
编号 |行索引 -----: | --------: 12.40 | 1 45.12 | 2 134.90 | 3 212.80 | 4 578.90 | 5 876.78 | 6
set @r=0;
select S.num
from (
    select num, case when num is not NULL then (@r:=@r+1) end as rowIndex
    from mytable T1
    order by num
    ) S
where rowIndex = ceil(@r/2);
|编号 | | -----: | | 134.90 |

dbfiddle here

如果我们删除订单,但是结果是不可预测的。例如

set @r=0;
select num, case when num is not NULL then (@r:=@r+1) end as rowIndex
from mytable T1
;
编号 |行索引 -----: | --------: 12.40 | 1 134.90 | 2 45.12 | 3 876.78 | 4 212.80 | 5 578.90 | 6
set @r=0;
select S.num
from (
    select num, case when num is not NULL then (@r:=@r+1) end as rowIndex
    from mytable T1
    ) S
where rowIndex = ceil(@r/2);
|编号 | | ----: | | 45.12 |

dbfiddle here

如果没有明确的 ORDER BY 子句,假设数字系列将根据需要进行排序是不安全的。它可能会发生,但你不能依赖它。

【讨论】:

  • 谢谢!但真正让我感到困惑的是,我认为select num, @r:=@r+1 end as rowIndex from mytable T1 order by num 会给我第二列1,3,2,5,6,4。但它给了1,2,3,4,5,6。我的意思是如果你只执行select num, @r:=@r+1 end as rowIndex from mytable T1,即没有order by num,输出的第二列仍然是1,2,3,4,5,6,对吗?那么我认为额外的order by是对派生表的操作,所以应该第二列1,2,3,4,5,6不是也按照num列的顺序重新排序吗?
  • “会给我第二列 1,3,2,5,6,4。” 不,不会。如果是这样,那么到达中点将完全没有用。使用这些变量受 order by 的影响。 - 谢天谢地。
  • 我知道,但是我想知道在sql中生成新表的顺序。所以select num, @r:=@r+1 end as rowIndex from mytable 应该生成一个包含 2 列的表,并且第一列是未排序的数字列表,第二列是 1,2,3,4,5,6 对吗?那么我们称这个表为T2,它应该是存储在内存中的吧?那么操作order by num,应该重新排列表T2 的行不是吗?那为什么这个重排不影响T2的第二列呢?
  • 您对操作顺序的假设不正确,MySQL“知道”查询结合了变量操作和 order by 所以它故意应用顺序然后计算变量和返回结果集,然后外部查询使用该结果集。经验证据就在你面前。
  • 我明白了。但是如果我只是想让新创建的第2列根据第1列的排序顺序重新排列(完全独立于本帖),那么MySQL应该如何解决这个问题呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 2019-04-23
  • 2016-04-03
  • 2013-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多