sql 统计一段时间内巡检次数 7 天内的不重复计算

2021-03-09 09:02:32 +08:00
 bwd1991
这个可以通过 sql 实现吗?感觉好困难
现在巡检记录是个单表结构
ID DeviceID DeviceName CreateUser CreateTime Remark CreateUserCode Dept_ID

19 4 电气箱 1 管理员 2019-03-18 09:18:34.997 admin 8
20 4 电气箱 1 管理员 2019-03-18 09:20:02.430 admin 8
21 4 电气箱 1 管理员 2019-03-18 10:13:19.313 admin 8
22 4 电气箱 1 管理员 2019-03-18 11:19:11.097 admin 8
2109 次点击
所在节点    数据库
26 条回复
TimePPT
2021-03-09 11:16:38 +08:00
@TimePPT row_number() over (partition by deviceid order by dt)
TimePPT
2021-03-09 11:19:12 +08:00
@TimePPT 这个思路的前提是先按天为周期去重
TimePPT
2021-03-09 12:57:37 +08:00
@TimePPT 囧,又想了下不太对,这个如果日期不连续还不能直接求
zhuangjia
2021-03-09 13:44:49 +08:00
借鉴了 MySQL 统计连续登录天数的思路和 sql,主要是这篇: https://zhuanlan.zhihu.com/p/32613190

生成测试数据

```
# 创建测试表
CREATE TABLE `tmp_test_lianxu_3` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`DeviceID` int(11) DEFAULT NULL,
`CreateTime` datetime DEFAULT NULL COMMENT '登录时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

# 生成测试数据

INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('1', '1', '2014-01-01 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('2', '1', '2014-01-02 15:37:57');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('3', '2', '2014-01-01 09:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('4', '2', '2014-01-02 09:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('5', '1', '2014-01-04 10:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('6', '1', '2014-01-05 12:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('7', '2', '2014-01-10 00:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('8', '2', '2014-01-11 13:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('10', '2', '2014-01-12 12:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('11', '1', '2014-01-08 06:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('12', '2', '2014-01-11 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('13', '2', '2014-01-15 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('14', '2', '2014-01-17 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('15', '2', '2014-01-19 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('16', '2', '2014-01-21 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('17', '2', '2014-01-26 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('18', '2', '2014-01-28 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('19', '2', '2014-01-30 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('20', '2', '2014-02-16 21:00:00');
INSERT INTO `test`.`tmp_test_lianxu_3` (`id`, `DeviceID`, `CreateTime`) VALUES ('21', '2', '2014-02-13 21:00:00');

```


sql 语句如下

```
SELECT
DeviceID,
# 检查每次巡检记录,如果最近一次巡检时间是 7 天前,那么有效巡检天数+1 ;如果是 7 天内,有效巡检天数+0 ;否则设置为 1
@cont_day := ( CASE
WHEN ( DATEDIFF(login_dt, @real_last_dt) > 7 ) THEN (@cont_day + 1)
WHEN ( DATEDIFF(login_dt, @real_last_dt) <= 7 ) THEN (@cont_day + 0)
ELSE 1
END
) AS days,
@last_did := DeviceID,
# 判断当前巡检是否为有效巡检(间隔 7 天),是则更新最后有效巡检时间;
# 如果不是则判断是否存在最后有效巡检时间,存在则不变,不存在则设置未当前巡检时间
@real_last_dt := ( CASE
WHEN ( DATEDIFF(login_dt, @real_last_dt) > 7 ) THEN login_dt
WHEN ( @real_last_dt > 0 ) THEN @real_last_dt
ELSE @last_dt
END
) as last_dt,
@last_dt := login_dt
FROM
( SELECT DeviceID, DATE(CreateTime) AS login_dt FROM tmp_test_lianxu_3
WHERE DeviceID=2 AND CreateTime BETWEEN "2014-01-01" AND "2014-01-31"
ORDER BY DeviceID, CreateTime ) AS t,
( SELECT @last_did := '', @last_dt := '', @real_last_dt := '', @cont_day := 0 ) AS t1

```

执行后结果如下:(其中 days 即为有效巡检天数)


DeviceID|days|@last_did := DeviceID|last_dt|@last_dt := login_dt
---|---|---|---|---
2|1|2||2014/1/1
2|1|2|2014/1/1|2014/1/2
2|2|2|2014/1/10|2014/1/10
2|2|2|2014/1/10|2014/1/11
2|2|2|2014/1/10|2014/1/11
2|2|2|2014/1/10|2014/1/12
2|2|2|2014/1/10|2014/1/15
2|2|2|2014/1/10|2014/1/17
2|3|2|2014/1/19|2014/1/19
2|3|2|2014/1/19|2014/1/21
2|3|2|2014/1/19|2014/1/26
2|4|2|2014/1/28|2014/1/28
2|4|2|2014/1/28|2014/1/30
zhuangjia
2021-03-09 13:47:46 +08:00
@zhuangjia 尴尬,忘了回复不支持 markdown,这个格式看着愁人
bwd1991
2021-03-10 10:41:34 +08:00
@zhuangjia 哈哈哈 辛苦了 最后解决方案是计算每个设备巡检的间隔天数

DECLARE
@date1 DATETIME
,@date2 DATETIME
,@days INT
SET @date1='2021-01-01'
SET @date2='2021-03-01'
SET @days=7
SELECT b.*,c.DeviceClassID,SUM(a.qscount) qsdays,DATEDIFF(DAY,@date1,@date2)/@days alldays FROM (

SELECT *,CASE WHEN DATEDIFF(DAY,tt.checkTime,tt.CreateTime)<=@days THEN 0 ELSE DATEDIFF(DAY,tt.checkTime,tt.CreateTime)/@days END qscount FROM
(SELECT t1.*
,CASE WHEN ISNULL((SELECT TOP 1 t2.CreateTime FROM dbo.xj_Check t2 WHERE t1.DeviceID=t2.DeviceID AND t2.ID<t1.ID ORDER BY t2.ID desc),t3.CreateTime)<@date1 THEN @date1
ELSE ISNULL((SELECT TOP 1 t2.CreateTime FROM dbo.xj_Check t2 WHERE t1.DeviceID=t2.DeviceID AND t2.ID<t1.ID ORDER BY t2.ID desc),t3.CreateTime) END checkTime
FROM xj_Check t1
INNER JOIN dbo.tb_DeviceList t3 ON t1.DeviceID=t3.DeviceID
WHERE t1.CreateTime BETWEEN @date1 AND @date2) tt
) a
INNER JOIN tb_DeviceList b ON a.DeviceID=b.DeviceID
INNER JOIN dbo.tb_DeviceType c ON b.DeviceType=c.ID
WHERE c.DeviceClassID=5
GROUP BY b.DeviceID,
b.DeviceName,
b.DeviceType,
b.DeviceTypeName,
b.Loaction,
b.CreateTime,
b.CreateUser,
b.MakerID,
b.MakerName,
b.IsEnable,
b.Admin,c.DeviceClassID
ORDER BY b.DeviceType,b.DeviceName

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/759812

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX