Sql server 从两天开始跳过假日和每周休假
我正在使用sql server 2008 R2,我正在创建申请休假表。当用户申请休假,即开始日期和结束日期,然后介于两个日期之间时,如果所有日期都是假日和每周休假,则应跳过所有日期Sql server 从两天开始跳过假日和每周休假,sql-server,Sql Server,我正在使用sql server 2008 R2,我正在创建申请休假表。当用户申请休假,即开始日期和结束日期,然后介于两个日期之间时,如果所有日期都是假日和每周休假,则应跳过所有日期 CREATE TABLE #HolidayMaster ( [HolidayID] [int] IDENTITY(1,1) NOT NULL, [HolidayDescription] [nvarchar](50) NULL, [HolidayDate] [date] NULL, ) IN
CREATE TABLE #HolidayMaster
(
[HolidayID] [int] IDENTITY(1,1) NOT NULL,
[HolidayDescription] [nvarchar](50) NULL,
[HolidayDate] [date] NULL,
)
INSERT INTO #HolidayMaster
select 'New Year', '2016-01-01'
union
select 'National Developer Day', '2016-01-05'
CREATE TABLE #ShiftMaster
(
[ShiftID] [int] IDENTITY(1,1) NOT NULL,
[Sunday] [float] NULL,
[Monday] [float] NULL,
[Tuesday] [float] NULL,
[Wednesday] [float] NULL,
[Thursday] [float] NULL,
[Friday] [float] NULL,
[Saturday] [float] NULL
)
INSERT INTO #ShiftMaster
select 0,1,1,1,1,1,0
select *,DATENAME (dw,[HolidayDate]) as [DayName] from #HolidayMaster
select * from #ShiftMaster
drop table #HolidayMaster
drop table #ShiftMaster
Declare @LeaveStartDate date = '2013-01-01'
Declare @LeaveEndDate date = '2013-01-06'
--expected out put
DName Date Desc
Friday 2016-01-01 Holiday
Saturday 2016-01-02 WeeklyOff
Sunday 2016-01-03 WeeklyOff
Monday 2016-01-04 Working
Tuesday 2016-01-05 Holiday
Wednesday 2016-01-06 Working
试试这个
DECLARE @LeaveStartDate DATETIME = '2016-01-01'
DECLARE @LeaveEndDate DATETIME = '2016-01-06'
;WITH CTE
AS ( SELECT @LeaveStartDate AS LeaveDate
UNION ALL
SELECT LeaveDate + 1
FROM CTE
WHERE LeaveDate < @LeaveEndDate
)
SELECT * ,DATENAME(WEEKDAY, c.LeaveDate)
FROM CTE c
LEFT JOIN #HolidayMaster h ON c.LeaveDate = h.HolidayDate
WHERE h.HolidayDate IS NULL
AND EXISTS ( SELECT 1
FROM #ShiftMaster s
WHERE (DATENAME(WEEKDAY, c.LeaveDate) = 'Sunday' AND s.Sunday = 1)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Monday' AND s.Monday = 1)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Tuesday' AND s.Tuesday = 1)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Wednesday' AND s.Wednesday = 1)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Thursday' AND s.Thursday = 1)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Friday' AND s.Friday = 1)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Saturday' AND s.Saturday = 1)
)
DECLARE @LeaveStartDate DATETIME = '2016-01-01'
DECLARE @LeaveEndDate DATETIME = '2016-01-06'
;WITH CTE
AS ( SELECT @LeaveStartDate AS LeaveDate
UNION ALL
SELECT LeaveDate + 1
FROM CTE
WHERE LeaveDate < @LeaveEndDate
)
SELECT
c.LeaveDate,
DATENAME(WEEKDAY, c.LeaveDate) AS [DayName],
CASE WHEN (DATENAME(WEEKDAY, c.LeaveDate) = 'Sunday' AND s.Sunday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Monday' AND s.Monday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Tuesday' AND s.Tuesday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Wednesday' AND s.Wednesday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Thursday' AND s.Thursday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Friday' AND s.Friday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Saturday' AND s.Saturday = 0)
THEN 'WeeklyOff'
WHEN h.HolidayDate IS NOT NULL
THEN 'Holiday'
ELSE 'Working'
END AS [Status]
FROM CTE c
CROSS JOIN #ShiftMaster s
LEFT JOIN #HolidayMaster h ON c.LeaveDate = h.HolidayDate
如果您希望获得所有状态为的日期,请尝试此选项
DECLARE @LeaveStartDate DATETIME = '2016-01-01'
DECLARE @LeaveEndDate DATETIME = '2016-01-06'
;WITH CTE
AS ( SELECT @LeaveStartDate AS LeaveDate
UNION ALL
SELECT LeaveDate + 1
FROM CTE
WHERE LeaveDate < @LeaveEndDate
)
SELECT
c.LeaveDate,
DATENAME(WEEKDAY, c.LeaveDate) AS [DayName],
CASE WHEN (DATENAME(WEEKDAY, c.LeaveDate) = 'Sunday' AND s.Sunday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Monday' AND s.Monday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Tuesday' AND s.Tuesday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Wednesday' AND s.Wednesday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Thursday' AND s.Thursday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Friday' AND s.Friday = 0)
OR (DATENAME(WEEKDAY, c.LeaveDate) = 'Saturday' AND s.Saturday = 0)
THEN 'WeeklyOff'
WHEN h.HolidayDate IS NOT NULL
THEN 'Holiday'
ELSE 'Working'
END AS [Status]
FROM CTE c
CROSS JOIN #ShiftMaster s
LEFT JOIN #HolidayMaster h ON c.LeaveDate = h.HolidayDate
你需要一张日历桌。我使用理货表生成日期
Declare @LeaveStartDate date = '2016-01-01'
Declare @LeaveEndDate date = '2016-01-06'
;WITH Nbrs_3( n ) AS ( SELECT 1 UNION SELECT 0 ),
Nbrs_2( n ) AS ( SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2 ),
Nbrs_1( n ) AS ( SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2 ),
Nbrs_0( n ) AS ( SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2 ),
Nbrs ( n ) AS ( SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2 ),
calendar(dates) as
(
SELECT Dateadd(dd, n - 1, @LeaveStartDate) AS Date
FROM (SELECT Row_number()OVER (ORDER BY n)
FROM Nbrs) D ( n )
WHERE n <= Datediff(day, @LeaveStartDate, @LeaveEndDate)+ 1
)
SELECT DName =d.day_name,
Date = c.dates,
CASE
WHEN HolidayDate IS NOT NULL THEN 'Holiday'
WHEN leav_iden = 0 THEN 'WeeklyOff'
WHEN HolidayDate IS NOT NULL
AND leav_iden = 0 THEN 'Holiday/WeeklyOff'
ELSE 'Working'
END AS [Desc]
FROM calendar c
JOIN (SELECT *
FROM #ShiftMaster
CROSS apply (VALUES ([Sunday],'Sunday'),
([Monday],'Monday'),
([Tuesday],'Tuesday'),
([Wednesday],'Wednesday'),
([Thursday],'Thursday'),
([Friday],'Friday'),
([Saturday],'Saturday') ) cs(leav_iden, day_name)) d
ON Datename(WEEKDAY, c.dates) = d.day_name
LEFT JOIN #HolidayMaster h
ON h.HolidayDate = c.dates
首先需要根据时间间隔生成日期。显示了一个快速的好方法。然后,您可以离开HolidayMaster表以检查某个日期是否为假日 代码应该如下所示:
Declare @LeaveStartDate date = '2016-01-01'
Declare @LeaveEndDate date = '2016-01-06'
;WITH Dates_CTE AS (
SELECT TOP (DATEDIFF(DAY, @LeaveStartDate, @LeaveEndDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @LeaveStartDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b
)
SELECT DATENAME (dw,[Date]) as [DayName],
[Date],
(CASE WHEN DATEPART(dw, [Date]) IN (1, 7) THEN 'WeeklyOff'
WHEN HM.HolidayID IS NOT NULL THEN 'Holiday' -- HM.Description can be used here to actually display holiday name
ELSE 'Working' END) [Desc]
FROM Dates_CTE D
LEFT JOIN #HolidayMaster HM ON HM.HolidayDate = D.[Date]
通常是左键连接。。IS NULL检查比NOT EXISTS慢,所以另一种方法是删除左连接并检查是否存在,但我发现这种形式更具可读性 递归CTE要在日期范围、HolidayMaster上的left join和ShiftMaster上的left join之间生成日期,我将ShiftMaster更改为具有要加入的日期名称,然后根据值选择适当的描述:
CREATE TABLE #HolidayMaster
(
[HolidayID] [int] IDENTITY(1,1) NOT NULL,
[HolidayDescription] [nvarchar](50) NULL,
[HolidayDate] [date] NULL,
)
INSERT INTO #HolidayMaster
select 'New Year', '2016-01-01'
union
select 'National Developer Day', '2016-01-05'
CREATE TABLE #ShiftMaster
(
[ShiftID] [int] IDENTITY(1,1) NOT NULL,
[Day] nvarchar(20) NULL,
IsHoliday bit NULL
)
INSERT INTO #ShiftMaster
values ('Sunday', 0), ('Monday', 1), ('Tuesday', 1), ('Wednesday',1), ('Thursday', 1), ('Friday', 1), ('Saturday',0)
select *,DATENAME (dw,[HolidayDate]) as [DayName] from #HolidayMaster
select * from #ShiftMaster
Declare @LeaveStartDate date = '2016-01-01'
Declare @LeaveEndDate date = '2016-01-06'
;WITH Dates AS (
SELECT
[Date] = @LeaveStartDate
UNION ALL SELECT
[Date] = DATEADD(DAY, 1, [Date])
FROM
Dates
WHERE
Date < @LeaveEndDate
) SELECT
DATENAME(dw, [Date])
, [Date]
, CASE WHEN hm.HolidayDescription IS NULL THEN
CASE WHEN sm.IsHoliday = 1 THEN 'Working' ELSE 'Weekly Off' END
ELSE 'Holiday' END AS Description
FROM
Dates
left join #HolidayMaster hm on hm.HolidayDate = [Date]
left join #ShiftMaster sm on sm.Day = DATENAME(dw, [Date])
drop table #HolidayMaster
drop table #ShiftMaster
试一试
你带硬编码的星期天和星期六,我需要动态。您能从班长daysname处带来日期名称吗0@Naweez,我已编辑查询以从中进行检查ShiftMaster@Naweez增加了另一种解决方案来获得所有日期与日期状态。可以添加一个额外的CTE为SHIVENTHOME样纳扎克以上,所以这样的代码将被简化。您没有考虑SHIFT MISTHY更改我的SHIFTHEMER表,我不想要
Declare @LeaveStartDate date = '2016-01-01'
Declare @LeaveEndDate date = '2016-01-06'
;with dts(dt) as (select @LeaveStartDate
union all
select dateadd(day,1,dt) from dts where dt<@LeaveEndDate),
shifmstr as (
select shiftID,'Sunday' as dname,[sunday] tp from #ShiftMaster union all
select shiftID,'Monday' ,Monday from #ShiftMaster union all
select shiftID,'Tuesday' ,Tuesday from #ShiftMaster union all
select shiftID,'Wednesday',Wednesday from #ShiftMaster union all
select shiftID,'Thursday',Thursday from #ShiftMaster union all
select shiftID,'Friday',Friday from #ShiftMaster union all
select shiftID,'Saturday',Saturday from #ShiftMaster)
select datename(dw,dt) DName,Dt,
case when c.HolidayDate is not null then 'Holiday'
when tp=1 then 'Working' else 'WeeklyOff' end descr
from dts a join shifmstr b on
datename(dw,a.dt)=b.dname left join
#HolidayMaster c on a.dt=c.HolidayDate