2016-11-22 1 views
1

모든 공휴일을 저장하는 테이블을 기준으로 한 달 내의 근무일 수를 계산하는 쿼리가 있습니다.조건부 조사 On Row_Number

현재 출력은 공휴일과 토요일과 일요일을 제외한 모든 근무일을 표시하지만, 매월 표시하고 싶지만 공휴일이나 토요일이나 일요일에는 증가하지 않습니다.

조건부로 행 번호를 늘리는 방법이 있습니까?

쿼리는 다음과 같습니다 : 의사 코드의

DECLARE @startnum INT=0 
DECLARE @endnum INT=365; 

WITH gen AS 
(
    SELECT @startnum AS num 
    UNION ALL 
    SELECT num + 1 
    FROM gen 
    WHERE num + 1 <= @endnum 
) 
, holidays AS 
( 
    SELECT CONVERT(DATE, transdate) AS HolidayDate 
    FROM WORKCALENDER w 
    WHERE w.CALENDARID = 'PubHoliday' 
) 
, allDays AS 
( 
    SELECT DATEADD(d, num, CONVERT(DATE, '1 Jan 2016')) AS DateOfYear 
    , DATENAME(dw, DATEADD(d, num, CONVERT(DATE, '1 Jan 2016'))) AS [dayOfWeek] 
    FROM gen 
) 
select number = ROW_NUMBER() OVER (ORDER BY DateOfYear )  
, * 
from allDays 
    LEFT OUTER JOIN holidays 
     ON allDays.DateOfYear = holidays.HolidayDate 
WHERE holidays.HolidayDate IS NULL 
    AND allDays.dayOfWeek NOT IN ('Saturday', 'Sunday') 
    AND DateOfYear >= CONVERT(DATE, '1 ' + DATENAME(MONTH, GETDATE()) + ' 2016') 
    AND DateOfYear < CONVERT(DATE, '1 ' + DATENAME(MONTH, DATEADD(month, 1, GETDATE())) + ' 2016') 
option (maxrecursion 10000) 
+2

일부 서식 지정은이 텍스트 벽에 대한 경이로움을 나타냅니다. 나는 이것을 읽을 수 있도록 포맷했고 훨씬 덜 혼란 스럽다. FWIW, 집계를 위해 재귀 cte 대신 집계표 또는 숫자 표를 사용해야합니다. 이 문제를 해결하려면 조금 더 자세하게 설명해야합니다. 가장 가능성이있는 것은 단지 날짜 만있는 것입니다. 모든 날짜의 목록에 합류 된 채로 남아있는 것으로 간주됩니다. –

+0

예 기존의 최종 선택 (행 번호 비트 빼기)을 다른 cte에 넣은 다음이 필터링 된 cte에서 선택하여 행 번호 추가) –

답변

0

종류

select date, row_number() over (order by date) as num 
from (select date 
     from allDates 
     where month = x and weekday 
     exept 
     select date 
     from holidays 
     where month is x 
    ) as t 
union all 
select date, null 
from holidays 
where month is x 
order by date 
0

당신은 WorkdaySequenceInMonth의 출력을 구성하는 방법을 참조하십시오, 윈도우를 합계를 사용할 수 있습니다.

DECLARE @startDate DATE = '20160101' 
     , @numDays INT = 365 
     , @num  INT = 0; 

DECLARE @Holidays TABLE (Holiday DATE); 

INSERT INTO @Holidays(Holiday) 
    VALUES ('20160101') 
      , ('20160115') 
      , ('20160714'); 

WITH nums AS 
(
    SELECT row_number() OVER (ORDER BY object_id) - 1 as num 
    FROM sys.columns 
), 
dateRange as 
(
    SELECT 
     DATEADD(DAY, num, @startDate) AS Dt 
    , num 
    FROM nums 
    WHERE num < @numDays 
), 
Parts AS 
(
    SELECT 
     R.Dt as [Date] 
     , Year(R.Dt) as [Year] 
     , Month(R.Dt) as [Month] 
     , Day(R.Dt) as [Day] 
     , Datename(weekday, R.Dt) as [Weekday] 
     , CASE WHEN H.Holiday IS NOT NULL 
        OR Datename(weekday, R.Dt) IN ('Saturday', 'Sunday') 
       THEN 0 
       ELSE 1 
       END AS IsWorkday 

    FROM dateRange R  
    LEFT JOIN @Holidays H ON R.Dt = H.Holiday 
) 
-- 
select 
    * 
    , sum(IsWorkday) over (PARTITION BY [Year],[month] 
          ORDER BY [Day] 
          ROWS UNBOUNDED PRECEDING) as WorkdaySequenceInMonth  
from Parts 
order by [Year], [Month] 
0

안녕하세요 당신은이 쿼리를 시도 할 수 있습니다. 초기 부분은 데이터 생성이며 아마도 필요하지 않습니다. 는 그럼 난 데이터

를 반환 그럼 그냥 간단한 쿼리 @StartYear, @EndYear 에서 설정 한 시간 동안 모든 날짜와 임시 테이블을 생성
  -- generate holidays table 
      select holiday 
      into #tempHolidays 
      from 
      (
      select '20160101' as holiday 
      union all 
      select '20160201' as holiday 
      union all 
      select '20160205' as holiday 
      union all 
      select '20160301' as holiday 
      union all 
      select '20160309' as holiday 
      union all 
      select '20160315' as holiday 
      ) as t 


      create table #tempCalendar (Date_temp date) 

      select * from 
      #tempHolidays 

      declare @startYear int , @endYear int, @i int, @dateStart datetime , @dateEnd datetime, @date datetime, @i = 0 
      Select @startYear = '2016' 
        ,@endYear = '2016' 
        ,@dateStart = (Select cast((cast(@startYear as varchar(4)) +'0101') as datetime)) 
        ,@dateEnd = (Select cast((cast(@startYear as varchar(4)) +'1231') as datetime)) 
        ,@date = @dateStart 


        --Insert dates of the period of time 
      while (@date <> @dateEnd) 
      begin 

      insert into #tempCalendar 
      Select @date 
      set @date = (select DATEADD(dd,1,@date)) 

      end 

      -- Retrive Date list 
      Select Date_temp 
      from #tempCalendar 
      where Date_temp not in (Select holiday from #tempHolidays) 
      and datename(weekday,Date_temp) not in ('Saturday','Sunday') 

      --REtrieve sum of working days per month 
      select DATEPART(year,Date_temp) as year 
        ,DATEPART(month,Date_temp) as Month 
        ,Count(*) as CountOfWorkingDays 

      from #tempCalendar 
      where Date_temp not in (Select holiday from #tempHolidays) 
      and datename(weekday,Date_temp) not in ('Saturday','Sunday') 
      Group by DATEPART(year,Date_temp) 
        ,DATEPART(month,Date_temp) 
당신은 당신의 휴일 테이블 및 사용 #tempHolidays을 변경해야합니다

@StarYear 및 @EndYear를 기간으로 사용하십시오.

0

여기에 비 휴일

IF OBJECT_ID('tempdb.dbo.#dates') IS NOT null 
    DROP TABLE #dates; 
CREATE TABLE #dates (d DATE); 

IF OBJECT_ID('tempdb.dbo.#holidays') IS NOT null 
    DROP TABLE #holidays; 
CREATE TABLE #holidays (d DATE); 

INSERT INTO [#holidays] 
     ([d]) 
VALUES 
    ('2016-12-25'), 
    ('2017-12-25'), 
    ('2018-12-25'); 

INSERT INTO [#dates] 
     ([d]) 
SELECT TOP 1000 DATEADD(DAY, n, '2015-12-31') 
FROM [Util].dbo.[Numbers] AS [n]; 


WITH holidays AS (
    SELECT d.*, CASE WHEN h.d IS NULL THEN 0 ELSE 1 END AS [IsHoliday] 
    FROM [#dates] AS [d] 
    LEFT JOIN [#holidays] AS [h] 
     ON [d].[d] = [h].[d] 
) 
SELECT d, ROW_NUMBER() OVER (PARTITION BY [holidays].[IsHoliday] ORDER BY d) 
FROM [holidays] 
ORDER BY d; 

위한 당신의 순서에 연속성을 유지하기 위해 partition by 조항의 사용을 보여줍니다 그리고 내 휴일로만 크리스마스를 표시 용서해주십시오 간단한 데모입니다!