【sql练习】计算时间差的秒数(考虑非工作日)

例如:审批开始时间是2020-02-07 20:09:57,结束时间是2020-02-10 22:30:30,请问审批共耗时多少秒?(扣除所有的法定节假日和周六日)

在mysql中进行测试

数据准备

节假日表数据

DROP TABLE IF EXISTS holiday_table;
CREATE TABLE holiday_table (
  DATE_ID date,
  DAY_WORK int,
  isWork varchar(50)
) ;

插入数据

INSERT INTO holiday_table VALUES ('2018-03-30 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-03-31 00:00:00',2,'放假'  );
INSERT INTO holiday_table VALUES ('2018-04-01 00:00:00',2,'放假'  );
INSERT INTO holiday_table VALUES ('2018-04-02 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-03 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-04 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-05 00:00:00',2,'放假'  );
INSERT INTO holiday_table VALUES ('2018-04-06 00:00:00',2,'放假'  );
INSERT INTO holiday_table VALUES ('2018-04-07 00:00:00',2,'放假'  );
INSERT INTO holiday_table VALUES ('2018-04-08 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-09 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-10 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-11 00:00:00',1,'工作日');
DATE_ID DAY_WORK isWork
2018-03-30 00:00:00 1 工作日
2018-03-31 00:00:00 2 放假
2018-04-01 00:00:00 2 放假
2018-04-02 00:00:00 1 工作日
2018-04-03 00:00:00 1 工作日
2018-04-04 00:00:00 1 工作日
2018-04-05 00:00:00 2 放假
2018-04-06 00:00:00 2 放假
2018-04-07 00:00:00 2 放假
2018-04-08 00:00:00 1 工作日
2018-04-09 00:00:00 1 工作日
2018-04-10 00:00:00 1 工作日

审批时间表数据

app_info 表存放审批信息的数据

DROP TABLE IF EXISTS app_info ;
CREATE TABLE app_info  (
  ID int,
  start_date TIMESTAMP,
  end_date TIMESTAMP
) ;

插入三条数据

INSERT INTO app_info VALUES (1,'2018-03-30 12:10:00','2018-04-02 17:10:00');
INSERT INTO app_info VALUES (2,'2018-04-02 11:00:05','2018-04-03 10:40:05');
INSERT INTO app_info VALUES (3,'2018-04-03 17:20:00','2018-04-11 11:10:05');

方法1

将日期表中的数据去关联假日表的数据,把非工作日的去除,剩下的条数就是工作日的天数。

1. 关联表取时间

SELECT
	A.id,
	A.start_date,
	A.end_date,
	B.DATE_ID AS Interval_date
from app_info A
join holiday_table B
on B.DATE_ID BETWEEN date(A.start_date) AND date(A.end_date)
	and B.DAY_WORK=1
id start_date end_date Interval_date
1 2018/3/30 12:10 2018/4/2 17:10 2018/3/30
1 2018/3/30 12:10 2018/4/2 17:10 2018/4/2
2 2018/4/2 11:00 2018/4/3 10:40 2018/4/2
2 2018/4/2 11:00 2018/4/3 10:40 2018/4/3
3 2018/4/3 17:20 2018/4/11 11:10 2018/4/3
3 2018/4/3 17:20 2018/4/11 11:10 2018/4/4
3 2018/4/3 17:20 2018/4/11 11:10 2018/4/8
3 2018/4/3 17:20 2018/4/11 11:10 2018/4/9
3 2018/4/3 17:20 2018/4/11 11:10 2018/4/10
3 2018/4/3 17:20 2018/4/11 11:10 2018/4/11

2. 统计天数

SELECT
	A.id,
	A.start_date,
	A.end_date,
	count(1) AS Interval_num
from app_info A
join holiday_table B
on B.DATE_ID BETWEEN date(A.start_date) AND date(A.end_date)
	and B.DAY_WORK=1
group by 
		A.id,
	A.start_date,
	A.end_date
id start_date end_date Interval_num
1 2018/3/30 12:10 2018/4/2 17:10 2
2 2018/4/2 11:00 2018/4/3 10:40 2
3 2018/4/3 17:20 2018/4/11 11:10 5

3.时间间隔的时间

所得的相差秒数应为 时间相差的秒数 减去 多算的工作日的天数对应的描述(即天数*24*60*60)

select
	id,
	start_date,
	end_date,
	TIMESTAMPDIFF(SECOND,start_date,end_date)-(DATEDIFF(end_date,start_date)+1-Interval_num)*24*60*60 AS Interval_sec
from
	(SELECT
		A.id,
		A.start_date,
		A.end_date,
		count(1) as Interval_num
	from app_info A
	join holiday_table B
	on B.DATE_ID BETWEEN date(A.start_date) AND date(A.end_date)
		and B.DAY_WORK=1
	group by 
			A.id,
		A.start_date,
		A.end_date) t

最终结果

id start_date end_date Interval_sec
1 2018-03-30 12:10:00 2018-04-02 17:10:00 104400
2 2018-04-02 11:00:05 2018-04-03 10:40:05 85200
3 2018-04-03 17:20:00 2018-04-11 11:10:05 409805

4. 如果提交审批是休息日

上述代码对于审批日是休息日,计算会有差错

插入例子

INSERT INTO app_info VALUES (4,'2018-04-01 09:20:00','2018-04-02 11:10:05');
INSERT INTO app_info VALUES (5,'2018-04-04 20:20:00','2018-04-05 11:10:05');

id为4不考虑休息日应为 39600+600+5=40205秒,用之前代码的得出的结果为6605秒 结果存在误差

id为5不考虑休息日应为10800+2400=13200秒

对代码进行进一步的处理

SELECT
	id,
	start_date,
	end_date,
	TIMESTAMPDIFF(SECOND,start_date_new,end_date_new)-(DATEDIFF(end_date_new,start_date_new)+1-Interval_num_new)*24*60*60 AS Interval_sec	
FROM
	(SELECT
		id,
		start_date,
		end_date,
		case when date(start_date) = first_workday then start_date else date_format(first_workday,'%Y-%m-%d %H:%i:%s') end AS start_date_new ,
		case when date(end_date) = last_workday then end_date else  date_format(last_workday,'%Y-%m-%d %H:%i:%s') end AS end_date_new,
		case when date(end_date) <> last_workday then Interval_num + 1 else Interval_num end AS Interval_num_new
	FROM
		(SELECT
			A.id,
			A.start_date,
			A.end_date,
			count(1) AS Interval_num,
			MIN(DATE_ID) AS first_workday,
			MAX(DATE_ID) AS last_workday
		FROM app_info A
		JOIN holiday_table B
		ON B.DATE_ID BETWEEN date(A.start_date) AND date(A.end_date) 
			AND B.DAY_WORK=1
		GROUP BY 
			A.id,
			A.start_date,
			A.end_date
		) t1
	) t2

id为4的结果为40205

id start_date end_date Interval_sec
1 2018-03-30 12:10:00 2018-04-02 17:10:00 104400
2 2018-04-02 11:00:05 2018-04-03 10:40:05 85200
3 2018-04-03 17:20:00 2018-04-11 11:10:05 409805
4 2018-04-01 09:20:00 2018-04-02 11:10:05 40205
5 2018/4/4 20:20 2018/4/5 11:10 13200

方法2

自定义函数

create  function getWorkDay
( 
    beginday date, 
    endday date
) 
returns int
begin
	declare Interval_num int;
    SELECT COUNT(1) from holiday_table WHERE DATE_ID BETWEEN beginday AND endday AND DAY_WORK=1 into Interval_num;
	return Interval_num;
end;

测试

select getWorkDay('2018-03-30 12:10:00','2018-04-02 17:10:00');

结果为2天,还需将天换算成对应的时分秒再进行其他的转换,暂时未写完此方法。

发布了35 篇原创文章 · 获赞 12 · 访问量 6621

猜你喜欢

转载自blog.csdn.net/u012955829/article/details/104163538