mysql - 嵌套 SQL 查询中的排序依据

标签 mysql sql sql-update sql-order-by window-functions

我想就我在 MySQL 中使用“order by”指令时遇到的一个奇怪的事实寻求您的帮助

让我们看看下表:

CREATE TABLE `test_nested_order_by` (
  `id` int(11) NOT NULL,
  `timestamp` int(11) NOT NULL COMMENT 'Timestamp',
  `index_continuity_month` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

insert into test_nested_order_by (id,timestamp,index_continuity_month) values (1,1583772141,0) ;
insert into test_nested_order_by (id,timestamp,index_continuity_month) values (1,1583708400,0) ;
insert into test_nested_order_by (id,timestamp,index_continuity_month) values (5,1583708400,0) ;
insert into test_nested_order_by (id,timestamp,index_continuity_month) values (4,1583708400,0) ;
insert into test_nested_order_by (id,timestamp,index_continuity_month) values (5,1583794800,0) ;
insert into test_nested_order_by (id,timestamp,index_continuity_month) values (4,1583794800,0) ;

如您所见,每行的“index_continuity_month”列都设置为 0 值。

我现在想按如下方式设置该值:一个唯一值,该值将按 id 和时间戳列的升序递增。该表看起来像:

mysql>  select * from test_nested_order_by :

+----+------------+------------------------+
| id | timestamp  | index_continuity_month |
+----+------------+------------------------+
|  1 | 1583772141 |                      2 |
|  1 | 1583708400 |                      1 |
|  5 | 1583708400 |                      5 |
|  4 | 1583708400 |                      3 |
|  5 | 1583794800 |                      6 |
|  4 | 1583794800 |                      4 |
+----+------------+------------------------+
6 rows in set (0,00 sec)

或者,如果您愿意:

mysql> select * from test_nested_order_by order by id,timestamp ;
+----+------------+------------------------+
| id | timestamp  | index_continuity_month |
+----+------------+------------------------+
|  1 | 1583708400 |                      1 |
|  1 | 1583772141 |                      2 |
|  4 | 1583708400 |                      3 |
|  4 | 1583794800 |                      4 |
|  5 | 1583708400 |                      5 |
|  5 | 1583794800 |                      6 |
+----+------------+------------------------+

为此,我使用此查询:

UPDATE  test_nested_order_by t1,
(SELECT
id,
timestamp,
@last_continuity_month := @last_continuity_month +1, @last_continuity_month AS index_continuity_month

FROM test_nested_order_by, (

SELECT @last_continuity_month :=0
)SQLVars
ORDER BY id , timestamp) t2

SET t1.index_continuity_month = t2.index_continuity_month

WHERE t1.id = t2.id
      AND t1.timestamp = t2.timestamp;

但是当我看到结果时,它似乎不起作用:

mysql> select * from test_nested_order_by order by id,timestamp ;
+----+------------+------------------------+
| id | timestamp  | index_continuity_month |
+----+------------+------------------------+
|  1 | 1583708400 |                      2 |
|  1 | 1583772141 |                      1 |
|  4 | 1583708400 |                      4 |
|  4 | 1583794800 |                      6 |
|  5 | 1583708400 |                      3 |
|  5 | 1583794800 |                      5 |
+----+------------+------------------------+
6 rows in set (0,00 sec)

我怀疑没有考虑“order by”指令(如果我从查询中删除它,结果是完全相同的)。

我们可以注意到,index_continuity_month的增量并不是按照id和timestamp列的升序进行的,而是按照行插入表中的顺序进行的。

但是,如果我只运行查询的嵌套部分:

SELECT
id,
timestamp,
@last_continuity_month := @last_continuity_month +1, @last_continuity_month AS index_continuity_month

FROM test_nested_order_by, (

SELECT @last_continuity_month :=0
)SQLVars
ORDER BY id , timestamp;

+----+------------+-----------------------------------------------------+------------------------+
| id | timestamp  | @last_continuity_month := @last_continuity_month +1 | index_continuity_month |
+----+------------+-----------------------------------------------------+------------------------+
|  1 | 1583708400 |                                                   1 |                      1 |
|  1 | 1583772141 |                                                   2 |                      2 |
|  4 | 1583708400 |                                                   3 |                      3 |
|  4 | 1583794800 |                                                   4 |                      4 |
|  5 | 1583708400 |                                                   5 |                      5 |
|  5 | 1583794800 |                                                   6 |                      6 |
+----+------------+-----------------------------------------------------+------------------------+

结果很好!

有谁可以帮我解释一下问题出在哪里吗?更具体地说,为什么 SQL 查询嵌套到另一个查询中时没有相同的行为?

非常感谢!

最佳答案

作为初学者:如果您运行的是 MySQL 8.0,则可以使用 row_number() 非常简单地完成此操作:

update test_nested_order_by t
inner join (
    select 
        t.*, 
        row_number() over(order by id, timestamp) rn 
    from test_nested_order_by t
) t1 on t1.id = t.id and t1.timestamp = t.timestamp
set t.index_continuity_month  = t1.rn 

在早期版本中,用户变量确实是一种解决方案;然而,将它们与 order by 一起使用是相当棘手的。这是因为 order by 通常在 select 子句之后处理,因此不能保证“正确”的值将被分配给每一行。要解决此问题,您需要首先在子查询中对表进行排序,然后设置变量:

update test_nested_order_by t
inner join (
    select t.*, @rn := @rn + 1 rn
    from (select * from test_nested_order_by order by id, timestamp) t
    cross join (select @rn := 0) x
) t1 on t1.id = t.id and t1.timestamp = t.timestamp
set t.index_continuity_month  = t1.rn 

<强> Demo on DB Fiddle - 两个更新查询都会产生以下结果:

select * from test_nested_order_by order by id, timestamp
id |  timestamp | index_continuity_month
-: | ---------: | ---------------------:
 1 | 1583708400 |                      1
 1 | 1583772141 |                      2
 4 | 1583708400 |                      3
 4 | 1583794800 |                      4
 5 | 1583708400 |                      5
 5 | 1583794800 |                      6

关于mysql - 嵌套 SQL 查询中的排序依据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61600059/

相关文章:

php - session 变量不返回

mysql - 在同一事务中插入和更新同一行? (MySQL)

sql - 为什么这个更新查询不起作用?

python - 将具有一些公共(public)字段的多个表组合成一个表

javascript - 获取 SQL 表值的最有效方法是什么?

mysql - Where 子句中的 SQL 更改条件

mysql - UPDATE 可以用不同的方式写吗?

python - 带有可变 WHERE 子句的批量更新表

mysql - 从 tmp 数据库中的表插入和更新到另一个数据库中的表

php - 在 if-else 中重新生成随机数(php)