问题说明:任给出两个时间(开始时间<结束时间),算出这个两个时间 的工作日时间差,节假日不算,非工作时间不算(例某公司上午上班时间8:30 - 12:00,下午上班时间:13:30 - 18:00,即只在这个排班时间 间的时间差)
问题应用考勤计算、流程耗时计算、工作日天数计算等

解题思路

  • 最后要的结果是时间差,用自定义函数解决
  • 分两种考虑,开始时间和结束时间在同一天和不在同一天
  • 开始/结束时间在同一天,分情况(一共16种,下面列出)计算
  • 开始/结束时间不在同一天,先计算两个时间间的工作日天数(不含首尾),再计算分别开始时间和结束时间所在工作日的 当天的时间差
  • 本次将定义四个自定义函数:①get_WorkTime 主函数(会调用另外三个函数) ②get_WorkDay 计算两个日期的工作日天数(不含首尾) ③get_WorkStrTime 计算开始时间的工作时间(开始/结束时间不在同一天情况) ④get_WorkEndTime 计算结束时间的工作时间(开始/结束时间不在同一天情况)

准备工作

函数中会用到日历表用来判断某一个日期是否为工作日,表(T_Calendar)的格式如下:

问题开始

定义get_WorkTime 主函数

--------------------------创建自定义标量函数计算两个具体时间的工作日(8小时)时间差---------------------
CREATE  FUNCTION [dbo].[get_WorkTime](@str_time datetime, @end_time datetime)
RETURNS int
AS
BEGINdeclare @am_str time, @am_end time ,@pm_str time ,@pm_end time,@day_str_type varchar(100),@day_end_type varchar(100),@myresult int--定义工作日上班时间段set @am_str='08:30:00.00' set @am_end='12:00:00.00'set @pm_str='13:30:00.00' set @pm_end='18:00:00.00'----定义开始时间结束时间测试--set @str_time='2018-11-06 17:59:00.00'--set @end_time='2018-11-08 08:30:00.00'set @day_str_type=(select a.日期类型 from T_Calendar a inner join  (select cast(@str_time as date) as fz) b  on a.日期=b.fz)set @day_end_type=(select a.日期类型 from T_Calendar a inner join  (select cast(@end_time as date) as fz) b  on a.日期=b.fz)-------------------------------------------------判断开始时间和结束时间是不是在同一天--------------------------------------------------if(CONVERT(VARCHAR(10),@str_time, 120) = CONVERT(VARCHAR(10),@end_time, 120))---------------------------------------------------开始和结束时间在同一天------------------------------------------判断是不是工作日if(@day_str_type='工作日')--开始时间在上午上班之前if cast(@end_time as time)<@am_str and  cast(@str_time as time)<@am_str   --开始时间在上午上班之前 and 结束时间在上午上班之前set @myresult=0else if cast(@end_time as time)<@am_end and  cast(@str_time as time)<@am_str  --开始在上午上班之前 and 结束在上午下班之前set @myresult=datediff(MINUTE,@am_str ,cast(@end_time as time))else if cast(@end_time as time)<@pm_str and  cast(@str_time as time)<@am_str  --开始在上午上班之前 and 结束在下午上班之前set @myresult=datediff(MINUTE,@am_str ,@am_end)else if cast(@end_time as time)<@pm_end and  cast(@str_time as time)<@am_str  --开始在上午上班之前 and 结束在下午下班之前set @myresult=datediff(MINUTE,@am_str ,@am_end)+datediff(MINUTE,@pm_str ,cast(@end_time as time))else if cast(@end_time as time)>@pm_end and  cast(@str_time as time)<@am_str  --开始在上午上班之前 and 结束在下午下班之后set @myresult=datediff(MINUTE,@am_str ,@am_end)+datediff(MINUTE,@pm_str ,@pm_end)--开始时间在上午下班之前else if cast(@end_time as time)<@am_end and  cast(@str_time as time)<@am_end  --开始在上午下班之前 and 结束在上午下班之前set @myresult=datediff(MINUTE,@str_time ,@end_time)else if cast(@end_time as time)<@pm_str and  cast(@str_time as time)<@am_end  --开始在上午下班之前 and 结束在下午上班之前set @myresult=datediff(MINUTE,cast(@str_time as time) ,@am_end)else if cast(@end_time as time)<@pm_end and  cast(@str_time as time)<@am_end  --开始在上午下班之前 and 结束在下午下班之前set @myresult=datediff(MINUTE,cast(@str_time as time) ,@am_end)+datediff(MINUTE,@pm_str ,cast(@end_time as time))else if cast(@end_time as time)>@pm_end and  cast(@str_time as time)<@am_end  --开始在上午下班之前 and 结束在下午下班之后set @myresult=datediff(MINUTE,cast(@str_time as time) ,@am_end)+datediff(MINUTE,@pm_str ,@pm_end)--开始时间在下午上班之前else if cast(@end_time as time)<@pm_str and  cast(@str_time as time)<@pm_str  --开始在下午上班之前 and 结束在下午上班之前set @myresult=0else if cast(@end_time as time)<@pm_end and  cast(@str_time as time)<@pm_str  --开始在下午上班之前 and 结束在下午下班之前set @myresult=datediff(MINUTE,@pm_str ,cast(@end_time as time))else if cast(@end_time as time)>@pm_end and  cast(@str_time as time)<@pm_str  --开始在下午上班之前 and 结束在下午下班之后set @myresult=datediff(MINUTE,@pm_str ,@pm_end)--开始时间在下午下班之前else if cast(@end_time as time)<@pm_end and  cast(@str_time as time)<@pm_end  --开始在下午下班之前 and 结束在下午下班之前set @myresult=datediff(MINUTE,cast(@str_time as time) ,cast(@end_time as time))else if cast(@end_time as time)>@pm_end and  cast(@str_time as time)<@pm_end  --开始在下午下班之前 and 结束在下午下班之后set @myresult=datediff(MINUTE,cast(@str_time as time)  ,@pm_end)--开始时间在下午下班之前(非工作时间)else set @myresult=0--在非工作日为0elseset @myresult=0-------------------------------------------开始和结束时间不在同一天  需调用另外3个自定义函数-----------------------------------------------------------elseset @myresult=dbo.get_WorkDay(cast(@str_time as date),cast(@end_time as date))*(datediff(MINUTE,@pm_str ,@pm_end)+datediff(MINUTE,@am_str ,@am_end))+dbo.get_WorkStrTime(@str_time) +dbo.get_WorkEndTime(@end_time)return @myresult
END

定义get_WorkDay 函数(T_Calendar 日历表)

CREATE  FUNCTION [dbo].[get_WorkDay](@str_date date,@end_date date)
RETURNS int
AS
BEGINdeclare @str_ID INT,@end_ID INT,@myresult intset @myresult=0set @str_ID=(select a.ID from T_Calendar a inner join  (select cast(@str_date as date) as fz) b  on a.日期=b.fz)set @end_ID=(select a.ID from T_Calendar a inner join  (select cast(@end_date as date) as fz) b  on a.日期=b.fz)declare   @id int,@日期 date,@日期类型 varchar(100)declare my_cur cursor--定义一个游标read_only for select id, 日期, 日期类型 from  T_Calendar where ID>@str_ID and ID<@end_ID --为所获得的数据集指定游标,ID为主键open my_cur--打开游标fetch next from my_cur into  @id,@日期,@日期类型 --读取第一行数据while(@@fetch_status=0)--返回被 FETCH 语句执行的最后游标的状态,而不是任何当前被连接打开的游标的状态。beginif(@日期类型='工作日') set @myresult=@myresult+1----提取下一位信息fetch next from my_cur into @id,@日期,@日期类型endclose my_cur--关闭游标deallocate my_cur--删除游标RETURN  @myresult
END

定义get_WorkStrTime函数

-----------------------创建自定义标量函数计算开始时间的工作时间----------------------
CREATE  FUNCTION [dbo].[get_WorkStrTime](@str_time datetime)
RETURNS int
AS
BEGINdeclare @am_str time, @am_end time ,@pm_str time ,@pm_end time,@day_str_type varchar(100),@myresult int--定义工作日上班时间段set @am_str='08:30:00.00' set @am_end='12:00:00.00'set @pm_str='13:30:00.00' set @pm_end='18:00:00.00'set @day_str_type=(select a.日期类型 from T_Calendar a inner join  (select cast(@str_time as date) as fz) b  on a.日期=b.fz)if(@day_str_type='工作日' and cast(@str_time as time)<@am_str)  --上午上班之前set @myresult=datediff(MINUTE,@am_str ,@am_end)+datediff(MINUTE,@pm_str ,@pm_end)                else if(@day_str_type='工作日' and cast(@str_time as time)<@am_end)  --上午下班之前set @myresult=datediff(MINUTE,cast(@str_time as time) ,@am_end)+datediff(MINUTE,@pm_str ,@pm_end)                     else if(@day_str_type='工作日' and cast(@str_time as time)<@pm_str)  --下午上班之前set @myresult=datediff(MINUTE,@pm_str ,@pm_end )             else if(@day_str_type='工作日' and cast(@str_time as time)<@pm_end)  --下午下班之前set @myresult=datediff(MINUTE,cast(@str_time as time),@pm_end)else if(@day_str_type='工作日' and cast(@str_time as time)>@pm_end)  --下午下班之后set @myresult=0   else set @myresult=0                          RETURN  @myresult
END

定义get_WorkEndTime函数

-----------------------创建自定义标量函数计算结束时间的工作时间----------------------
CREATE  FUNCTION [dbo].[get_WorkEndTime](@end_time datetime)
RETURNS int
AS
BEGINdeclare @am_str time, @am_end time ,@pm_str time ,@pm_end time,@day_str_type varchar(100),@myresult int--定义工作日上班时间段set @am_str='08:30:00.00' set @am_end='12:00:00.00'set @pm_str='13:30:00.00' set @pm_end='18:00:00.00'set @day_str_type=(select a.日期类型 from T_Calendar a inner join  (select cast(@end_time as date) as fz) b  on a.日期=b.fz)if(@day_str_type='工作日' AND cast(@end_time as time)<@am_str)  --上午上班之前set @myresult=0           else if(@day_str_type='工作日' AND  cast(@end_time as time)<@am_end)  --上午下班之前set @myresult=datediff(MINUTE,@am_str ,cast(@end_time as time))                 else if(@day_str_type='工作日' AND cast(@end_time as time)<@pm_str)  --下午上班之前set @myresult=datediff(MINUTE,@am_str ,@am_end)      else if(@day_str_type='工作日' AND  cast(@end_time as time)<@pm_end)  --下午下班之前set @myresult=datediff(MINUTE,@am_str ,cast(@am_end as time))+datediff(MINUTE,@pm_str ,cast(@end_time as time))else if(@day_str_type='工作日' AND  cast(@end_time as time)>@pm_end)  --下午下班之后set @myresult=datediff(MINUTE,@am_str ,cast(@am_end as time))+datediff(MINUTE,@pm_str ,@pm_end)                            else set @myresult=0RETURN  @myresult
END

应用测试

测试代码如下:

 declare @str_time datetime, @end_time datetime set @str_time='2019-07-16 17:30:00.00'set @end_time='2019-07-16 18:30:00.00'select dbo.get_WorkTime(@str_time, @end_time)

测试结果:工作日时间差为 30 分钟 OK!

注意事项

主函数运行的前提是另外三个函数创建.

工作日时间差/考勤计算(SQL 自定义函数)相关推荐

  1. sql 自定义函数 示例_SQL滞后函数概述和示例

    sql 自定义函数 示例 In the article SQL Server Lead function overview and examples, we explored Lead functio ...

  2. sql自定义函数学习思路_学习SQL:用户定义的函数

    sql自定义函数学习思路 You can create several user-defined objects in a database. One of these is definitely u ...

  3. sql 自定义函数 示例_SQL Server Choose()函数介绍和示例

    sql 自定义函数 示例 In the article, a CASE statement in SQL, we explored one of the important logical expre ...

  4. MS SQL自定义函数IsPositiveInteger MS SQL自定义函数IsNumeric 水晶报表使用IEnumerableT数据源...

    MS SQL自定义函数IsPositiveInteger 判断字符串是否为正整数,0开始的的数字不算. SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ...

  5. sql 自定义函数 示例_SQL Server SESSION_CONTEXT()函数与示例

    sql 自定义函数 示例 This article explores the SQL Server session context function, SESSION_CONTEXT() and pe ...

  6. spark SQL自定义函数:

    spark SQL 自定义函数: 自定义函数: 第一种:  U D F  (用户自定义函数)函数 特点:  一对一的关系,输入一个值以后输出一个值  (一进一出) 大部分的内置函数都是U D F函数 ...

  7. Spark SQL自定义函数_第五章

    1.自定义函数分类 类似于hive当中的自定义函数, spark同样可以使用自定义函数来实现新的功能. spark中的自定义函数有如下3类 1.UDF(User-Defined-Function) 输 ...

  8. Spark SQL自定义函数

    文章目录 自定义函数分类 自定义UDF 自定义UDAF[了解] 自定义函数分类 类似于hive当中的自定义函数, spark同样可以使用自定义函数来实现新的功能. spark中的自定义函数有如下3类 ...

  9. Oracle使用PL/SQL自定义函数

    这里写目录标题 一.PL/SQL概述 二.变量和常量 2.1变量 2.2赋值方式 2.3常量 2.4常量和变量的区别 三,%type和%rowtype 3.1 %type 3.2 %rowtype 四 ...

  10. php自定义函数数学计算,ThinkPHP自定义函数解决模板标签加减运算的方法

    本文实例讲述了ThinkPHP自定义函数解决模板标签加减运算的方法.分享给大家供大家参考.具体如下: 实际项目中,我们经常需要标签变量加减运算的操作.但是,在ThinkPHP中,并不支持模板变量直接运 ...

最新文章

  1. opencv学习笔记(二)
  2. C examples
  3. 5.3多线程条件变量
  4. Alpine Linux 使用简介
  5. kaggle和colab入门
  6. SAP根据用户名查姓名
  7. 【极品手机推荐】安卓3G运存16G内存,相机1300+500,三星高画质显示J7109|J7108
  8. c 语言 volatile 关键字
  9. 【C++】简易GIF生成器(斗图神器!必备!!!)持续更新~
  10. 世达03017数字万用表的使用
  11. 计算基因组外显子长度
  12. 2021-01-22
  13. 企微群机器人定时提醒
  14. win10 SystemParametersInfo 设置屏保 不好使_[教程]win10 ,ubuntu双系统安装避坑指南
  15. 关于pd.read_csv() 读数据的注意事项
  16. MyBatis-Plus 扩展篇 > 自动填充功能
  17. 最大后验估计(MAP)
  18. 电力电子技术——电力电子器件概述
  19. PHP建站集成软件包
  20. Check Problems---二分

热门文章

  1. 基于vue的h5网页微信分享链接图标丢失问题解决
  2. 新的笔记本电脑没有计算机,最新出炉!2020年10款最轻的笔记本电脑:轻就对了,是您想的吗?...
  3. linux系统时间编程(2) 各种时间标准GMT、UTC、世界时、TAI
  4. 什么是长元音和短元音
  5. Codeforces407C Curious Array
  6. 用java判断闰年和平年
  7. 李宏毅机器学习【深度学习】(0)【机器学习】
  8. python换源之pip.conf
  9. 基于三层交换技术的校园网设计与实现
  10. 剑网三客户端修复连接服务器失败,剑网3客户端异常 无法打开处理解决办法