подсчет количества недель на основе настроенных выходных - PullRequest
0 голосов
/ 01 сентября 2018

В разных организациях могут быть разные выходные. Так что, в этом случае нужно настроить выходной день. Для этого я попробовал Sql запрос напишите ниже

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

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

Из приведенного выше запроса я могу получить свой конкретный выходной.

например:

если пятница или любой другой день упоминается как выходные, то с пятницы по четверг соответствует неделя, и мне нужно выяснить, сколько полных недель в месяце? Или через год?

Я хочу получить количество недель на основе настроенной недели.

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Альтернативное решение,

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'
0 голосов
/ 01 сентября 2018

Во-первых, вам нужно сделать календарь на весь год или на целый месяц, поэтому я бы использовал cte recursion , чтобы сделать это.

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 дней в неделю, что бы ни начиналось с любой недели, тогда мы увидим эту проблему Пробелы и острова , потому что номер недели будет повторяться от 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 |

final, мы просто получаем все 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

Результаты

| 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 recursion дата больше 100, вы получите ошибку

Заявление прекращено. Максимальная рекурсия 100 была исчерпана до завершения оператора.

вы можете установить

option (maxrecursion 0)

Case When число 0 и 1 означают ваш выходной день

...