sql跳过非工作日(周末和节假日)
简介:场景1:基于开始日期和工期,推算结束日期。 场景2:基于开始日期和结束日期,计算工期 注:需要自己做界面维护工作日表(s_WorkDay)和节假日表(s_SpecialDay)
涉及到的数据表
IF OBJECT_ID('s_WorkDay') IS NULL
BEGIN
CREATE TABLE s_WorkDay([Monday] [TINYINT]
,[Tuesday] [TINYINT]
,[Wednesday] [TINYINT]
,[Thursday] [TINYINT]
,[Friday] [TINYINT]
,[Saturday] [TINYINT]
,[Sunday] [TINYINT]
)
END
GO
IF OBJECT_ID('s_SpecialDay') IS NULL
BEGIN
CREATE TABLE s_SpecialDay([SpecialDayGUID] [UNIQUEIDENTIFIER] PRIMARY KEY CLUSTERED NOT NULL
,[BeginDate] [DATETIME]
,[EndDate] [DATETIME]
,[IsWorkDay] [TINYINT]
,[Remarks] [VARCHAR](200)
)
END
GO
场景1:根据开始日期和工期,计算结束日期
--根据开始日期推出结束日期
IF EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[fn_GetEndDate]') AND xtype IN ( N'FN', N'IF', N'TF' ) )
DROP FUNCTION [dbo].[fn_GetEndDate]
GO
CREATE FUNCTION fn_GetEndDate ( @date DATETIME,@Duration INT )
RETURNS DATETIME
AS
BEGIN
DECLARE @Edate DATETIME
DECLARE @IsAdd INT
SET @Edate=@date
SET @Duration=@Duration-1
DECLARE @NoWorkDay TABLE(iDay int)
--非工作日枚举
INSERT INTO @NoWorkDay(iDay) SELECT * FROM dbo.fn_NoWorkDay()
WHILE ( @Duration > 0 )
BEGIN
SET @IsAdd=0
--默认往后+1
SET @Edate=DATEADD(day, 1, @Edate)
--如果非工作日,重复循环,否则跳下一步
IF EXISTS( SELECT TOP 1 1 FROM s_workDay WHERE DATEPART(weekday, @Edate) NOT IN (SELECT * FROM @NoWorkDay))
BEGIN
SET @IsAdd=1
SET @Duration = @Duration - 1
END
--如果当前日期在特殊非工作日中,则不跳
IF EXISTS( SELECT TOP 1 1 FROM s_SpecialDay WHERE (@Edate BETWEEN begindate AND enddate) AND IsWorkDay=0 AND @IsAdd=1)
BEGIN
SET @Duration = @Duration + 1
END
--如果当前日期在特殊工作日中,则跳1
IF EXISTS( SELECT TOP 1 1 FROM s_SpecialDay WHERE (@Edate BETWEEN begindate and enddate) AND IsWorkDay=1 AND @IsAdd=0)
BEGIN
SET @Duration = @Duration -1
END
END
RETURN @Edate
END
GO
场景2:根据两个日期,计算工期
--计算工期
IF EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[fn_GetDuration]') AND xtype IN ( N'FN', N'IF', N'TF' ) )
DROP FUNCTION [dbo].[fn_GetDuration]
GO
CREATE FUNCTION fn_GetDuration(@BeginDate DATETIME,@EndDate DATETIME)
RETURNS INT
AS
BEGIN
DECLARE @iCount INT
--A:取出常规工作日
SELECT @iCount = ISNULL(dbo.fn_GetWorkDay(@BeginDate, @EndDate), 0)
--B:减去特殊非工作日
SELECT @iCount = @iCount
- ISNULL(SUM(dbo.fn_GetWorkDay(CASE WHEN begindate < @BeginDate
THEN @BeginDate
ELSE begindate
END,
CASE WHEN enddate > @EndDate
THEN @EndDate
ELSE enddate
END)), 0)
FROM s_SpecialDay
WHERE isworkday = 0
AND SpecialDayGUID NOT IN (
SELECT SpecialDayGUID
FROM s_SpecialDay
WHERE ( begindate > @EndDate
AND enddate > @EndDate
)
OR ( begindate < @BeginDate
AND enddate < @BeginDate
) )
----C:加上特殊工作日
SELECT @iCount = @iCount + ISNULL(SUM(DATEDIFF(dd,
CASE WHEN begindate < @BeginDate
THEN @BeginDate
ELSE begindate
END,
CASE WHEN enddate > @EndDate
THEN @EndDate
ELSE enddate
END)
- dbo.fn_GetWorkDay(CASE
WHEN begindate < @BeginDate
THEN @BeginDate
ELSE begindate
END,
CASE
WHEN enddate > @EndDate
THEN @EndDate
ELSE enddate
END)), 0)
FROM s_SpecialDay
WHERE isworkday = 1
AND SpecialDayGUID NOT IN (
SELECT SpecialDayGUID
FROM s_SpecialDay
WHERE ( begindate > @EndDate
AND enddate > @EndDate
)
OR ( begindate < @BeginDate
AND enddate < @BeginDate
) )
RETURN @iCount
END
GO
需要用到的函数
IF EXISTS ( SELECT *
FROM dbo.sysobjects
WHERE id = OBJECT_ID(N'[dbo].[fn_NoWorkDay]')
AND xtype IN ( N'FN', N'IF', N'TF' ) )
DROP FUNCTION [dbo].[fn_NoWorkDay]
GO
--输出非工作日
CREATE FUNCTION fn_NoWorkDay()
RETURNS @NoWorkDay TABLE ( iDay INT )
AS
BEGIN
INSERT INTO @NoWorkDay
( iDay
)
SELECT 2
FROM s_WorkDay
WHERE Monday = 0
INSERT INTO @NoWorkDay
( iDay
)
SELECT 3
FROM s_WorkDay
WHERE Tuesday = 0
INSERT INTO @NoWorkDay
( iDay
)
SELECT 4
FROM s_WorkDay
WHERE Wednesday = 0
INSERT INTO @NoWorkDay
( iDay
)
SELECT 5
FROM s_WorkDay
WHERE Thursday = 0
INSERT INTO @NoWorkDay
( iDay
)
SELECT 6
FROM s_WorkDay
WHERE Friday = 0
INSERT INTO @NoWorkDay
( iDay
)
SELECT 7
FROM s_WorkDay
WHERE Saturday = 0
INSERT INTO @NoWorkDay
( iDay
)
SELECT 1
FROM s_WorkDay
WHERE Sunday = 0
RETURN
END
Go
--计算工作日
IF EXISTS ( SELECT *
FROM dbo.sysobjects
WHERE id = OBJECT_ID(N'[dbo].[fn_GetWorkDay]')
AND xtype IN ( N'FN', N'IF', N'TF' ) )
DROP FUNCTION [dbo].[fn_GetWorkDay]
GO
CREATE FUNCTION fn_GetWorkDay(@BeginDate DATETIME,@EndDate DATETIME)
RETURNS INT
AS
BEGIN
DECLARE @NoWorkDay TABLE(iDay int)
--非工作日枚举
INSERT INTO @NoWorkDay(iDay) SELECT * FROM fn_NoWorkDay()
DECLARE @i INT,@iCount INT
SET @iCount=0
SET @i = DATEDIFF(day, @BeginDate, @EndDate)
WHILE ( @i >= 0 )
BEGIN
--如果开始日期往后顺延,遇到非工作日,则不计数
IF EXISTS( SELECT TOP 1 1 FROM s_workDay WHERE DATEPART(weekday, @BeginDate) NOT IN (SELECT * FROM @NoWorkDay))
BEGIN
SET @iCount=@iCount+1
END
SET @BeginDate=DATEADD(day, 1, @BeginDate)
SET @i = @i - 1
END
RETURN @iCount
END
go
sql跳过非工作日(周末和节假日)的更多相关文章
- SQL计算时间差并排除周末
SQL计算时间差并排除周末 CREATE FUNCTION DI_FN_GET_WorkDay (@begin DATETIME , @end DATETIME ) RETURNS int BEGIN ...
- java获取n个工作日后的日期, 排除周末和节假日(顺延)
一.写在前面 需求: 工作需要获取n个工作日后的日期, 需要排除weekend和holiday, holiday存在数据库中, 存入的形式是一个节日有起始日期和截止日期(以下文中有关于节假日的表截图) ...
- 写sql语句分别按日,星期,月,季度,年统计
--写sql语句分别按日,星期,月,季度,年统计销售额 --按日 ' group by day([date]) --按周quarter ' group by datename(week,[date]) ...
- 数据库:sql语句分别按日,按周,按月,按季统计金额
如: 表:consume_record 字段:consume (money类型) date (datetime类型) 请问怎么写四条sql语句分别按日,按周,按月,按季统计消费总量. 如:1月 120 ...
- Oracle笔记 八、PL/SQL跳转/判断/循环语句块
--goto跳转语句 --在goto 后,跳转到相应的语句,然后执行该语句和后面所有语句 begin dbms_output.put_line('goto开始了'); goto c; --不被执行 d ...
- 一条SQL语句中算日销售额和月销售额
刚刚做项目的时候用到的 用户表:用户ID,用户名,余额 流水表:时间,用户ID,用户名,类型(0充值,1消费),变更金额 现在要查每个用户的日销售额和月销售额,本来最简单的方法是先把所有用户查出来,然 ...
- SQL实现一年中每个日期剔除节假日和星期天之后的五个日期是多少
最近公司OA系统的需求,实现一年中每个日期剔除节假日和星期天之后的五个日期是几号,每个日期都要跳过节假日和星期天,当时是真的慌了,郁闷了一天,后来半夜忽然来灵感,想想还是可以实现. 需要做一张节假日的 ...
- c# 计算两日期的工作时间间隔(排除非工作日)及计算下一个工作时间点.
一个日期段如工作时间为 8:00 至 17:00 public class TimeHelper { /// <summary> /// 计算时间间隔 /// </summary&g ...
- SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套”
误区 #26: SQL Server中存在真正的“事务嵌套”错误 嵌套事务可不会像其语法表现的那样看起来允许事务嵌套.我真不知道为什么有人会这样写代码,我唯一能够想到的就是某个哥们对SQL Serve ...
随机推荐
- linux下u盘检測程序
获得U盘的插入或者拔取得信息的传统方法是在内核级执行hotplug程序.相关參数通过环境变量传递过来,再由hotplug通知其它关注hotplug的应用程序,可是效率比較低. ...
- 初学Larevel 2014-08-21 11:24 90人阅读 评论(0) 收藏
添加第一个路由时就遇到了 404错误,查了一下说要这样才能 版权声明:本文为博主原创文章,未经博主允许不得转载.
- Android中Gallery和ImageSwitcher同步自动(滚动)播放图片库
本文主要内容是如何让Gallery和ImageSwitcher控件能够同步自动播放图片集 ,看起来较难,然而,实现的方法非常简单, 请跟我慢慢来.总的来说,本文要实现的效果如下图:(截图效果不怎么好) ...
- Ubuntu 16.04 实现有线 无线同时用
因为工作的原因,经常会用有线网卡连接服务器进行配置,无线网卡上外网. 一.查看当前网关信息 pipci@ubuntu:~$ ip route showdefault via 192.168.2.1 d ...
- 好吧,左小波出山了——ie8兼容indexOf问题
我,还是一个不懂世事的毛头小子,第一次写博.万事开头难,没事咱慢慢来.咳,练文笔吗.我觉得写东西最锻炼逻辑思维,我是一个不善于表达的人,可能是程序员的通病,但你看看人家王小波,八九十年代的作家兼职程序 ...
- Vuejs2.0构建一个彩票查询WebAPP(2)
一,Vuex的使用 import Vue from 'vue' import Vuex from 'vuex' import MsgModules from './MsgModules' Vue.us ...
- JS之闭包详细解读
闭包在红宝书中的解释就是:有权访问另一个函数作用域中的变量的函数. 1.变量作用域 全局变量:所有的函数外部定义的变量,它的作用域是整个script. 局部变量:定义在函数体内部的变量,作用域仅限于函 ...
- iOS Scheme 跳转主流实现方案
iOS Scheme跳转主流实现方案主要是路由跳转,目前iOS常用路由框架是JLRouter.HHRouter.MGJRouter. 但是这些路由库都各有不足,首先是JLRouter,用不到的功能繁多 ...
- ArcGIS Engine能够做什么?
转自原文ArcGIS Engine能够做什么? ArcGIS Engine是一组跨平台的嵌入式ArcObjects,它是ArcGIS软件产品的底层组件,用来构建定制的GIS和桌面制图应用程序,或是向原 ...
- Python 查找Twitter中特定话题中最流行的10个转发Tweet
CODE: #!/usr/bin/python # -*- coding: utf-8 -*- ''' Created on 2014-7-4 @author: guaguastd @name: fi ...