实现前后行相减的SQL该如何写?有两种方法!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35440678/article/details/86483963

背景

有时会有这样一种查询场景,需要对查询结果前后行操作,比如后一行减前一行。
比如有一张用户登录表,有登入和登出两行,需要相减简单计算在线时长。或者一张订单表,需要计算后一行的订单id和前一行的订单id差多少(假设订单号是单调递增的)。

针对这类场景,SQL语句改如何写呢?

表结构和数据构造

以统计前后行的订单号是否连续为例,
表结构:

CREATE TABLE `t_test3` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `order_id` int(11) DEFAULT '0' COMMENT '订单号',
  PRIMARY KEY (`id`),
  key (`order_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='';

插入测试数据:

insert into t_test3(order_id) values(1),(2),(3),(5),(6),(4),(2);

第一种写法:select 子查询

找order_id-1行,如果没有,说明不存在order_id-1的order_id

mysql>select *, (select t1.order_id-order_id from t_test3 where order_id=t1.order_id-1 order by order_id desc limit 1) diff from t_test3 t1;

+----+----------+------+
| id | order_id | diff |
+----+----------+------+
|  1 |        1 | NULL |
|  2 |        2 |    1 |
|  7 |        2 |    1 |
|  3 |        3 |    1 |
|  4 |        5 | NULL |
|  6 |        5 | NULL |
|  5 |        6 |    1 |
+----+----------+------+
7 rows in set (0.00 sec)

不过,这种写法有个缺点,不能再按diff过滤,会报错。

mysql> select *, (select order_id-t1.order_id from t_test3 where order_id=t1.order_id-1 order by order_id desc limit 1) diff from t_test3 t1 where diff is null;
ERROR 1054 (42S22): Unknown column 'diff' in 'where clause'

第二种写法:left/right join

order_idorder_id-1作为join条件

mysql> select * from t_test3 t1 left join (select * from t_test3  ) t2  on t1.order_id = t2.order_id-1 ;
+----+----------+------+----------+
| id | order_id | id   | order_id |
+----+----------+------+----------+
|  1 |        1 |    2 |        2 |
|  1 |        1 |    7 |        2 |
|  2 |        2 |    3 |        3 |
|  7 |        2 |    3 |        3 |
|  4 |        5 |    5 |        6 |
|  6 |        5 |    5 |        6 |
|  3 |        3 | NULL |     NULL |
|  5 |        6 | NULL |     NULL |
+----+----------+------+----------+
8 rows in set (0.00 sec)

如果只查找不存在的orderid,则直接加where条件:

mysql> select * from t_test3 t1 left join (select * from t_test3  ) t2  on t1.order_id = t2.order_id-1 where t2.order_id is null;
+----+----------+------+----------+
| id | order_id | id   | order_id |
+----+----------+------+----------+
|  3 |        3 | NULL |     NULL |
|  5 |        6 | NULL |     NULL |
+----+----------+------+----------+
2 rows in set (0.00 sec)

轻松搞定!

注意事项

一定要注意字段的类型,如果是字符串类型,又涉及到运算的则可能不会使用到索引。需要强转回char比较

  select u1.id,u1.detail_id,(select detail_id from t_order_detail where status=1 and create_time>='2019-01-09 16:00:00' 
  and create_time<='2019-01-09 16:01:00' 
   -- 类型转换
  and CONVERT((CAST(detail_id AS signed)-1),char(100))=u1.detail_id
      ) as diff
  from t_order_detail u1 where status=1  
 and create_time>='2019-01-09 16:00:00' 
and create_time<='2019-01-09 16:10:00';
select u1.id,u2.id,u1.detail_id,u2.detail_id  from t_order_detail u1 right join   
(select id,CONVERT((CAST(detail_id AS signed)-1),char(100)) detail_id from t_order_detail where status=1  
and create_time>='2019-01-09 16:00:00' 
and create_time<='2019-01-09 16:01:00')  u2 
on u1.detail_id=u2.detail_id where u1.detail_id is null  limit 100;

猜你喜欢

转载自blog.csdn.net/qq_35440678/article/details/86483963
今日推荐