跳过假期&每两周约会一次

时间:2016-06-29 05:35:25

标签: sql-server

我正在使用sql server 2008 R2,我正在创建应用程序休假表单。当用户申请休假时,即开始日期&结束日期然后在两个日期之间,所有日期应该跳过,如果他们在假期&每周关闭

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

5 个答案:

答案 0 :(得分:1)

您需要一张calendar表格。我用tally表来生成日期。

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 

结果:

DName       Date        Desc
-----       ----------  -------------
Sunday      2016-01-03  WeeklyOff
Monday      2016-01-04  Working
Tuesday     2016-01-05  Holiday
Wednesday   2016-01-06  Working
Friday      2016-01-01  Holiday
Saturday    2016-01-02  WeeklyOff

答案 1 :(得分:0)

试试这个,

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

答案 2 :(得分:0)

首先需要根据间隔生成日期。显示了一个很好的快速方式here。然后,您可以使用#HolidayMaster表LEFT JOIN来检查日期是否是假日。

代码应如下所示:

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]

通常LEFT JOIN .. IS NULL检查比NOT EXISTS慢,所以另一种方法是删除LEFT JOIN并检查是否存在,但我觉得这种形式更具可读性。

答案 3 :(得分:0)

递归CTE生成日期范围之间的日期,HolidayMaster上的左连接和ShiftMaster上的左连接(我更改了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

答案 4 :(得分:0)

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