版权声明:本文为博主原创文章,未经博主允许不得转载。 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_id
和order_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;