根据自定义的周末计算周数

时间:2018-09-01 06:32:15

标签: c# sql sql-server date weekday

不同的组织可能会有不同的一周休息时间。 因此,在这种情况下,需要自定义休假。为此,我尝试了 SQL查询写在下面

DECLARE @dayName VARCHAR(9);
SET @dayName = DATEName(DW, GETDATE());

IF(@dayName = 'Friday' OR @dayName = 'Saturday') 
    PRINT 'Weekend';
ELSE
    PRINT 'NOT Weekend';

从上面的查询中,我可以得到特定的休假。

例如:

如果提到星期五或其他任何一天作为周末,那么从星期五到星期四对应一个星期,我需要找出一个月中有多少完整的星期?还是一年?

我想根据自定义的weekOff获取星期数。

2 个答案:

答案 0 :(得分:2)

首先,您需要将日历设置为整年或整月,因此我将使用 cte递归进行设置。

SELECT DATEADD(month, DATEDIFF(month, 0, getdate()), 0) AS StartOfMonth,
       DATEADD(mm,1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)) - 1  AS EndOfMonth
UNION ALL
SELECT StartOfMonth +1 , EndOfMonth
FROM CTE 
WHERE StartOfMonth < EndOfMonth

一周中有7天,无论从任何一周开始,都将看到Gaps and Islands problem,因为周数将从1重复到7

因此,我将CASE WHEN与DateName to make your customer week date number, which number starts on Friday`配合使用,或根据您的逻辑使用。

 ;WITH CTE AS (
      SELECT DATEADD(month, DATEDIFF(month, 0, getdate()), 0) AS StartOfMonth,
             DATEADD(mm,1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)) - 1  AS EndOfMonth
      UNION ALL
      SELECT StartOfMonth +1 , EndOfMonth
      FROM CTE 
      WHERE StartOfMonth < EndOfMonth
    )
 SELECT *,
          CASE DateName(DW, StartOfMonth)
              WHEN 'Friday' THEN 0
              WHEN 'Saturday' THEN 1
              WHEN 'Sunday' THEN 2
              WHEN 'Monday' THEN 3
              WHEN 'Tuesday' THEN 4
              WHEN 'Wednesday' THEN 5
              WHEN 'Thursday' THEN 6
              WHEN 'Tuesday' THEN 7 
          END grp,
           ROW_NUMBER() OVER(ORDER BY StartOfMonth) rn
    FROM CTE

[结果]

|         StartOfMonth |           EndOfMonth | grp | rn |
|----------------------|----------------------|-----|----|
| 2018-09-01T00:00:00Z | 2018-09-30T00:00:00Z |   1 |  1 |
| 2018-09-02T00:00:00Z | 2018-09-30T00:00:00Z |   2 |  2 |
| 2018-09-03T00:00:00Z | 2018-09-30T00:00:00Z |   3 |  3 |
| 2018-09-04T00:00:00Z | 2018-09-30T00:00:00Z |   4 |  4 |
| 2018-09-05T00:00:00Z | 2018-09-30T00:00:00Z |   5 |  5 |
| 2018-09-06T00:00:00Z | 2018-09-30T00:00:00Z |   6 |  6 |
| 2018-09-07T00:00:00Z | 2018-09-30T00:00:00Z |   0 |  7 |
| 2018-09-08T00:00:00Z | 2018-09-30T00:00:00Z |   1 |  8 |
| 2018-09-09T00:00:00Z | 2018-09-30T00:00:00Z |   2 |  9 |
| 2018-09-10T00:00:00Z | 2018-09-30T00:00:00Z |   3 | 10 |
| 2018-09-11T00:00:00Z | 2018-09-30T00:00:00Z |   4 | 11 |
| 2018-09-12T00:00:00Z | 2018-09-30T00:00:00Z |   5 | 12 |
| 2018-09-13T00:00:00Z | 2018-09-30T00:00:00Z |   6 | 13 |
| 2018-09-14T00:00:00Z | 2018-09-30T00:00:00Z |   0 | 14 |
| 2018-09-15T00:00:00Z | 2018-09-30T00:00:00Z |   1 | 15 |
| 2018-09-16T00:00:00Z | 2018-09-30T00:00:00Z |   2 | 16 |
| 2018-09-17T00:00:00Z | 2018-09-30T00:00:00Z |   3 | 17 |
| 2018-09-18T00:00:00Z | 2018-09-30T00:00:00Z |   4 | 18 |
| 2018-09-19T00:00:00Z | 2018-09-30T00:00:00Z |   5 | 19 |
| 2018-09-20T00:00:00Z | 2018-09-30T00:00:00Z |   6 | 20 |
| 2018-09-21T00:00:00Z | 2018-09-30T00:00:00Z |   0 | 21 |
| 2018-09-22T00:00:00Z | 2018-09-30T00:00:00Z |   1 | 22 |
| 2018-09-23T00:00:00Z | 2018-09-30T00:00:00Z |   2 | 23 |
| 2018-09-24T00:00:00Z | 2018-09-30T00:00:00Z |   3 | 24 |
| 2018-09-25T00:00:00Z | 2018-09-30T00:00:00Z |   4 | 25 |
| 2018-09-26T00:00:00Z | 2018-09-30T00:00:00Z |   5 | 26 |
| 2018-09-27T00:00:00Z | 2018-09-30T00:00:00Z |   6 | 27 |
| 2018-09-28T00:00:00Z | 2018-09-30T00:00:00Z |   0 | 28 |
| 2018-09-29T00:00:00Z | 2018-09-30T00:00:00Z |   1 | 29 |
| 2018-09-30T00:00:00Z | 2018-09-30T00:00:00Z |   2 | 30 |    

然后我们可以尝试使用rn - grp来获取连续的组。

[结果]

|         StartOfMonth |           EndOfMonth | grp |
|----------------------|----------------------|-----|
| 2018-09-01T00:00:00Z | 2018-09-30T00:00:00Z |   0 |
| 2018-09-02T00:00:00Z | 2018-09-30T00:00:00Z |   0 |
| 2018-09-03T00:00:00Z | 2018-09-30T00:00:00Z |   0 |
| 2018-09-04T00:00:00Z | 2018-09-30T00:00:00Z |   0 |
| 2018-09-05T00:00:00Z | 2018-09-30T00:00:00Z |   0 |
| 2018-09-06T00:00:00Z | 2018-09-30T00:00:00Z |   0 |
| 2018-09-07T00:00:00Z | 2018-09-30T00:00:00Z |   7 |
| 2018-09-08T00:00:00Z | 2018-09-30T00:00:00Z |   7 |
| 2018-09-09T00:00:00Z | 2018-09-30T00:00:00Z |   7 |
| 2018-09-10T00:00:00Z | 2018-09-30T00:00:00Z |   7 |
| 2018-09-11T00:00:00Z | 2018-09-30T00:00:00Z |   7 |
| 2018-09-12T00:00:00Z | 2018-09-30T00:00:00Z |   7 |
| 2018-09-13T00:00:00Z | 2018-09-30T00:00:00Z |   7 |
| 2018-09-14T00:00:00Z | 2018-09-30T00:00:00Z |  14 |
| 2018-09-15T00:00:00Z | 2018-09-30T00:00:00Z |  14 |
| 2018-09-16T00:00:00Z | 2018-09-30T00:00:00Z |  14 |
| 2018-09-17T00:00:00Z | 2018-09-30T00:00:00Z |  14 |
| 2018-09-18T00:00:00Z | 2018-09-30T00:00:00Z |  14 |
| 2018-09-19T00:00:00Z | 2018-09-30T00:00:00Z |  14 |
| 2018-09-20T00:00:00Z | 2018-09-30T00:00:00Z |  14 |
| 2018-09-21T00:00:00Z | 2018-09-30T00:00:00Z |  21 |
| 2018-09-22T00:00:00Z | 2018-09-30T00:00:00Z |  21 |
| 2018-09-23T00:00:00Z | 2018-09-30T00:00:00Z |  21 |
| 2018-09-24T00:00:00Z | 2018-09-30T00:00:00Z |  21 |
| 2018-09-25T00:00:00Z | 2018-09-30T00:00:00Z |  21 |
| 2018-09-26T00:00:00Z | 2018-09-30T00:00:00Z |  21 |
| 2018-09-27T00:00:00Z | 2018-09-30T00:00:00Z |  21 |
| 2018-09-28T00:00:00Z | 2018-09-30T00:00:00Z |  28 |
| 2018-09-29T00:00:00Z | 2018-09-30T00:00:00Z |  28 |
| 2018-09-30T00:00:00Z | 2018-09-30T00:00:00Z |  28 |

最后,我们只得到月份或年份中的所有count(*) = 7组,这意味着整周。


查询1

整月

;WITH CTE AS (
  SELECT DATEADD(month, DATEDIFF(month, 0, getdate()), 0) AS StartOfMonth,
         DATEADD(mm,1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)) - 1  AS EndOfMonth
  UNION ALL
  SELECT StartOfMonth +1 , EndOfMonth
  FROM CTE 
  WHERE StartOfMonth < EndOfMonth
)
SELECT COUNT(*) fullweekAmount from (
  SELECT 
      MIN(StartOfMonth) startdt,
      MAX(StartOfMonth) enddt
  FROM (
    SELECT *,
          ROW_NUMBER() OVER(ORDER BY StartOfMonth) - 
          CASE DateName(DW, StartOfMonth)
              WHEN 'Friday' THEN 0
              WHEN 'Saturday' THEN 1
              WHEN 'Sunday' THEN 2
              WHEN 'Monday' THEN 3
              WHEN 'Tuesday' THEN 4
              WHEN 'Wednesday' THEN 5
              WHEN 'Thursday' THEN 6
              WHEN 'Tuesday' THEN 7 
          END grp
    FROM CTE
  ) t1
  GROUP BY grp
  having count(*) = 7
) t1

Results

| fullweekAmount |
|----------------|
|              3 |

全年

;WITH CTE AS (
  SELECT  DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS StartOfMonth,
          DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) + 1, -1)  - 1  AS EndOfMonth
  UNION ALL
  SELECT StartOfMonth +1 , EndOfMonth
  FROM CTE 
  WHERE StartOfMonth < EndOfMonth
)
SELECT COUNT(*) fullweekAmount from (
  SELECT 
      MIN(StartOfMonth) startdt,
      MAX(StartOfMonth) enddt
  FROM (
    SELECT *,
          ROW_NUMBER() OVER(ORDER BY StartOfMonth) - 
          CASE DateName(DW, StartOfMonth)
              WHEN 'Friday' THEN 0
              WHEN 'Saturday' THEN 1
              WHEN 'Sunday' THEN 2
              WHEN 'Monday' THEN 3
              WHEN 'Tuesday' THEN 4
              WHEN 'Wednesday' THEN 5
              WHEN 'Thursday' THEN 6
              WHEN 'Tuesday' THEN 7 
          END grp
    FROM CTE
  ) t1
  GROUP BY grp
  having count(*) = 7
) t1

option (maxrecursion 0)

sqlfiddle

注意

如果 cte递归日期超过100,则会收到错误消息

  

该语句终止。语句完成之前,最大递归100已用尽。

您可以设置

option (maxrecursion 0)

Case When数字01表示您的休假日

答案 1 :(得分:2)

替代解决方案

DECLARE @StartDate DATE='20200722'--any valid date as your requirement needs(it is inclusive of the specified date)
DECLARE @MonthorYear CHAR='Y'--Valid inputs: 'M'->for month and 'Y'-> for year
DECLARE @WeekdayBeginning nVarchar(15)='Sunday'
----Valid inputs run the following query, in my case it is english, for you it may differ based on your language
--SELECT DATENAME(dw, DATEADD(d,-1,'20180903')) Union all
--SELECT DATENAME(dw, DATEADD(d,0,'20180903')) Union all
--SELECT DATENAME(dw, DATEADD(d,1,'20180903')) Union all
--SELECT DATENAME(dw, DATEADD(d,2,'20180903')) Union all
--SELECT DATENAME(dw, DATEADD(d,3,'20180903')) Union all
--SELECT DATENAME(dw, DATEADD(d,4,'20180903')) Union all
--SELECT DATENAME(dw, DATEADD(d,5,'20180903')) 


DECLARE @week TABLE
(ID int identity(0,1),DoW nVarchar(15),isWeekstart bit default 0)

INSERT INTO @week (DoW)
SELECT DATENAME(dw, DATEADD(d,-1,'20180903')) Union all
SELECT DATENAME(dw, DATEADD(d,0,'20180903')) Union all
SELECT DATENAME(dw, DATEADD(d,1,'20180903')) Union all
SELECT DATENAME(dw, DATEADD(d,2,'20180903')) Union all
SELECT DATENAME(dw, DATEADD(d,3,'20180903')) Union all
SELECT DATENAME(dw, DATEADD(d,4,'20180903')) Union all
SELECT DATENAME(dw, DATEADD(d,5,'20180903')) 

-- input validations
if not exists (SELECT 1 FROM @week where  DoW=@WeekdayBeginning)
BEGIN
    PRINT 'Invalid @WeekdayBeginning input'
    RETURN
END 
if (@MonthorYear NOT IN ('M','Y'))
BEGIN
    PRINT 'Invalid @MonthorYear input'
    RETURN
END 

--Start of find logic
DECLARE @EndDate date
DECLARE @DaysMissed tinyint,@TempDays smallint,@Weeks tinyint

SELECT  @EndDate=
    case @MonthorYear WHEN 'M' THEN EOMONTH(@StartDate)
    ELSE DATEFROMPARTS(YEAR(@StartDate),12,31) END

UPDATE @week set isWeekstart=1 where Dow=@WeekdayBeginning
SELECT @TempDays=DATEDIFF(d,@StartDate,@EndDate)+1

if not exists(SELECT 1 FROM @week WHERE DATENAME(dw,@StartDate)=DoW and isWeekstart=1)
BEGIN
    DECLARE @tempID tinyint,@WeekstartID tinyint
    SELECT @tempID=ID from @week WHERE DATENAME(dw,@StartDate)=DoW
    SELECT @WeekstartID=ID from @week WHERE isWeekstart=1
    WHILE(@WeekstartID<>@tempID)
    BEGIN
        SET @TempDays=@TempDays-1
        SET @tempID=@tempID+1
        if(@tempID>6)
        BEGIN
            SET @tempID=0
        END
    END
END
SET @Weeks=@TempDays/7
SELECT @Weeks as 'CompleteWeeks'