我有一个查询,根据存储所有公共假日的表计算一个月内的工作日数。
当前输出将显示所有工作日,不包括公众假期以及周六和周日,我希望显示每月的每一天,但不会在公众假期或周六或周日递增。
有没有办法有条件地增加行号?
查询如下:
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)
答案 0 :(得分: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
答案 1 :(得分: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]
答案 2 :(得分: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作为您的时间段。
答案 3 :(得分:0)
这是一个简单的演示,演示如何使用partition by
子句在非假期的排序中保持连续性
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;
请原谅我的标记只有圣诞节作为假期!