sql跳过非工作日(周末和节假日)——转载

 

简介:场景1:基于开始日期和工期,推算结束日期。 场景2:基于开始日期和结束日期,计算工期 注:需要自己做界面维护工作日表(s_WorkDay)和节假日表(s_SpecialDay)  

涉及到的数据表 

 
  1. IF OBJECT_ID('s_WorkDay') IS NULL

  2. BEGIN

  3. CREATE TABLE s_WorkDay([Monday] [TINYINT]

  4. ,[Tuesday] [TINYINT]

  5. ,[Wednesday] [TINYINT]

  6. ,[Thursday] [TINYINT]

  7. ,[Friday] [TINYINT]

  8. ,[Saturday] [TINYINT]

  9. ,[Sunday] [TINYINT]

  10. )

  11. END

  12. GO

  13.  
  14. IF OBJECT_ID('s_SpecialDay') IS NULL

  15. BEGIN

  16. CREATE TABLE s_SpecialDay([SpecialDayGUID] [UNIQUEIDENTIFIER] PRIMARY KEY CLUSTERED NOT NULL

  17. ,[BeginDate] [DATETIME]

  18. ,[EndDate] [DATETIME]

  19. ,[IsWorkDay] [TINYINT]

  20. ,[Remarks] [VARCHAR](200)

  21. )

  22. END

  23. GO

场景1:根据开始日期和工期,计算结束日期 

 
  1. --根据开始日期推出结束日期

  2.  
  3. IF EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[fn_GetEndDate]') AND xtype IN ( N'FN', N'IF', N'TF' ) )

  4.  
  5. DROP FUNCTION [dbo].[fn_GetEndDate]

  6.  
  7. GO

  8.  
  9. CREATE FUNCTION fn_GetEndDate ( @date DATETIME,@Duration INT )

  10.  
  11. RETURNS DATETIME

  12.  
  13. AS

  14.  
  15. BEGIN

  16.  
  17. DECLARE @Edate DATETIME

  18.  
  19. DECLARE @IsAdd INT

  20.  
  21. SET @Edate=@date

  22.  
  23. SET @Duration=@Duration-1

  24.  
  25. DECLARE @NoWorkDay TABLE(iDay int)

  26.  
  27. --非工作日枚举

  28.  
  29. INSERT INTO @NoWorkDay(iDay) SELECT * FROM dbo.fn_NoWorkDay()

  30.  
  31.  
  32.  
  33. WHILE ( @Duration > 0 )

  34.  
  35. BEGIN

  36.  
  37. SET @IsAdd=0

  38.  
  39. --默认往后+1

  40.  
  41. SET @Edate=DATEADD(day, 1, @Edate)

  42.  
  43. --如果非工作日,重复循环,否则跳下一步

  44.  
  45. IF EXISTS( SELECT TOP 1 1 FROM s_workDay WHERE DATEPART(weekday, @Edate) NOT IN (SELECT * FROM @NoWorkDay))

  46.  
  47. BEGIN

  48.  
  49. SET @IsAdd=1

  50.  
  51. SET @Duration = @Duration - 1

  52.  
  53. END

  54.  
  55. --如果当前日期在特殊非工作日中,则不跳

  56.  
  57. IF EXISTS( SELECT TOP 1 1 FROM s_SpecialDay WHERE (@Edate BETWEEN begindate AND enddate) AND IsWorkDay=0 AND @IsAdd=1)

  58.  
  59. BEGIN

  60.  
  61. SET @Duration = @Duration + 1

  62.  
  63. END

  64.  
  65. --如果当前日期在特殊工作日中,则跳1

  66.  
  67. IF EXISTS( SELECT TOP 1 1 FROM s_SpecialDay WHERE (@Edate BETWEEN begindate and enddate) AND IsWorkDay=1 AND @IsAdd=0)

  68.  
  69. BEGIN

  70.  
  71. SET @Duration = @Duration -1

  72.  
  73. END

  74.  
  75. END

  76.  
  77. RETURN @Edate

  78.  
  79. END

  80.  
  81. GO

场景2:根据两个日期,计算工期 

 
  1. --计算工期

  2.  
  3. IF EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[fn_GetDuration]') AND xtype IN ( N'FN', N'IF', N'TF' ) )

  4.  
  5. DROP FUNCTION [dbo].[fn_GetDuration]

  6.  
  7. GO

  8.  
  9. CREATE FUNCTION fn_GetDuration(@BeginDate DATETIME,@EndDate DATETIME)

  10.  
  11. RETURNS INT

  12.  
  13. AS

  14.  
  15. BEGIN

  16.  
  17. DECLARE @iCount INT

  18.  
  19. --A:取出常规工作日

  20.  
  21. SELECT @iCount = ISNULL(dbo.fn_GetWorkDay(@BeginDate, @EndDate), 0)

  22.  
  23.  
  24.  
  25. --B:减去特殊非工作日

  26.  
  27. SELECT @iCount = @iCount

  28.  
  29. - ISNULL(SUM(dbo.fn_GetWorkDay(CASE WHEN begindate < @BeginDate

  30.  
  31. THEN @BeginDate

  32.  
  33. ELSE begindate

  34.  
  35. END,

  36.  
  37. CASE WHEN enddate > @EndDate

  38.  
  39. THEN @EndDate

  40.  
  41. ELSE enddate

  42.  
  43. END)), 0)

  44.  
  45. FROM s_SpecialDay

  46.  
  47. WHERE isworkday = 0

  48.  
  49. AND SpecialDayGUID NOT IN (

  50.  
  51. SELECT SpecialDayGUID

  52.  
  53. FROM s_SpecialDay

  54.  
  55. WHERE ( begindate > @EndDate

  56.  
  57. AND enddate > @EndDate

  58.  
  59. )

  60.  
  61. OR ( begindate < @BeginDate

  62.  
  63. AND enddate < @BeginDate

  64.  
  65. ) )

  66.  
  67.  
  68.  
  69. ----C:加上特殊工作日

  70.  
  71. SELECT @iCount = @iCount + ISNULL(SUM(DATEDIFF(dd,

  72.  
  73. CASE WHEN begindate < @BeginDate

  74.  
  75. THEN @BeginDate

  76.  
  77. ELSE begindate

  78.  
  79. END,

  80.  
  81. CASE WHEN enddate > @EndDate

  82.  
  83. THEN @EndDate

  84.  
  85. ELSE enddate

  86.  
  87. END)

  88.  
  89. - dbo.fn_GetWorkDay(CASE

  90.  
  91. WHEN begindate < @BeginDate

  92.  
  93. THEN @BeginDate

  94.  
  95. ELSE begindate

  96.  
  97. END,

  98.  
  99. CASE

  100.  
  101. WHEN enddate > @EndDate

  102.  
  103. THEN @EndDate

  104.  
  105. ELSE enddate

  106.  
  107. END)), 0)

  108.  
  109. FROM s_SpecialDay

  110.  
  111. WHERE isworkday = 1

  112.  
  113. AND SpecialDayGUID NOT IN (

  114.  
  115. SELECT SpecialDayGUID

  116.  
  117. FROM s_SpecialDay

  118.  
  119. WHERE ( begindate > @EndDate

  120.  
  121. AND enddate > @EndDate

  122.  
  123. )

  124.  
  125. OR ( begindate < @BeginDate

  126.  
  127. AND enddate < @BeginDate

  128.  
  129. ) )

  130.  
  131. RETURN @iCount

  132.  
  133. END

  134.  
  135. GO

需要用到的函数 

 
  1. IF EXISTS ( SELECT *

  2.  
  3. FROM dbo.sysobjects

  4.  
  5. WHERE id = OBJECT_ID(N'[dbo].[fn_NoWorkDay]')

  6.  
  7. AND xtype IN ( N'FN', N'IF', N'TF' ) )

  8.  
  9. DROP FUNCTION [dbo].[fn_NoWorkDay]

  10.  
  11. GO

  12.  
  13. --输出非工作日

  14.  
  15. CREATE FUNCTION fn_NoWorkDay()

  16.  
  17. RETURNS @NoWorkDay TABLE ( iDay INT )

  18.  
  19. AS

  20.  
  21. BEGIN

  22.  
  23. INSERT INTO @NoWorkDay

  24.  
  25. ( iDay

  26.  
  27. )

  28.  
  29. SELECT 2

  30.  
  31. FROM s_WorkDay

  32.  
  33. WHERE Monday = 0

  34.  
  35. INSERT INTO @NoWorkDay

  36.  
  37. ( iDay

  38.  
  39. )

  40.  
  41. SELECT 3

  42.  
  43. FROM s_WorkDay

  44.  
  45. WHERE Tuesday = 0

  46.  
  47. INSERT INTO @NoWorkDay

  48.  
  49. ( iDay

  50.  
  51. )

  52.  
  53. SELECT 4

  54.  
  55. FROM s_WorkDay

  56.  
  57. WHERE Wednesday = 0

  58.  
  59. INSERT INTO @NoWorkDay

  60.  
  61. ( iDay

  62.  
  63. )

  64.  
  65. SELECT 5

  66.  
  67. FROM s_WorkDay

  68.  
  69. WHERE Thursday = 0

  70.  
  71. INSERT INTO @NoWorkDay

  72.  
  73. ( iDay

  74.  
  75. )

  76.  
  77. SELECT 6

  78.  
  79. FROM s_WorkDay

  80.  
  81. WHERE Friday = 0

  82.  
  83. INSERT INTO @NoWorkDay

  84.  
  85. ( iDay

  86.  
  87. )

  88.  
  89. SELECT 7

  90.  
  91. FROM s_WorkDay

  92.  
  93. WHERE Saturday = 0

  94.  
  95. INSERT INTO @NoWorkDay

  96.  
  97. ( iDay

  98.  
  99. )

  100.  
  101. SELECT 1

  102.  
  103. FROM s_WorkDay

  104.  
  105. WHERE Sunday = 0

  106.  
  107. RETURN

  108.  
  109. END

  110.  
  111.  
  112.  
  113. Go

  114.  
  115. --计算工作日

  116.  
  117. IF EXISTS ( SELECT *

  118.  
  119. FROM dbo.sysobjects

  120.  
  121. WHERE id = OBJECT_ID(N'[dbo].[fn_GetWorkDay]')

  122.  
  123. AND xtype IN ( N'FN', N'IF', N'TF' ) )

  124.  
  125. DROP FUNCTION [dbo].[fn_GetWorkDay]

  126.  
  127. GO

  128.  
  129. CREATE FUNCTION fn_GetWorkDay(@BeginDate DATETIME,@EndDate DATETIME)

  130.  
  131. RETURNS INT

  132.  
  133. AS

  134.  
  135. BEGIN

  136.  
  137. DECLARE @NoWorkDay TABLE(iDay int)

  138.  
  139. --非工作日枚举

  140.  
  141. INSERT INTO @NoWorkDay(iDay) SELECT * FROM fn_NoWorkDay()

  142.  
  143. DECLARE @i INT,@iCount INT

  144.  
  145. SET @iCount=0

  146.  
  147. SET @i = DATEDIFF(day, @BeginDate, @EndDate)

  148.  
  149. WHILE ( @i >= 0 )

  150.  
  151. BEGIN

  152.  
  153. --如果开始日期往后顺延,遇到非工作日,则不计数

  154.  
  155. IF EXISTS( SELECT TOP 1 1 FROM s_workDay WHERE DATEPART(weekday, @BeginDate) NOT IN (SELECT * FROM @NoWorkDay))

  156.  
  157. BEGIN

  158.  
  159. SET @iCount=@iCount+1

  160.  
  161. END

  162.  
  163. SET @BeginDate=DATEADD(day, 1, @BeginDate)

  164.  
  165. SET @i = @i - 1

  166.  
  167. END

  168.  
  169. RETURN @iCount

  170.  
  171. END

  172.  
  173.  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值