SQL填充每月减去节假日总工作日为当前财政年度(SQL populate total working

2019-10-31 13:36发布

我是一个视图将看起来像我的第一个附加的图片然而,随着人口的右手列,而不是空白之后。 逻辑如下:

该数据必须在财政期间。 Therfore四月将在2011年三月将是2012等等。

对于天可用于单月计算将是:

总数的工作日(周一至周五)减去任何银行假日落入特定的月份,针对特定财政年度(我们都保存在一个表格 - 参见图2)。

节日表的列名左至右:holidaytypeid, 名称 ,holstart,holend。 表名:holidaytable

要制定出累计个月的日子可用“这将是单月已经填充数据求和的情况。 例如,四月至五月将是四月和五月的数据总结等等等等。

我需要在完美的格式SQL查询,使这可以直粘贴,将工作(即正确的列名和表名)

感谢您寻找。

Answer 1:

DECLARE @StartDate DATETIME, @EndDate DATETIME

SELECT  @StartDate = '01/04/2011',
        @EndDate = '31/03/2012'

CREATE TABLE #Data (FirstDay DATETIME NOT NULL PRIMARY KEY, WorkingDays INT NOT NULL)

;WITH DaysCTE ([Date]) AS
(   SELECT  @StartDate
    UNION ALL
    SELECT  DATEADD(DAY, 1, [Date])
    FROM    DaysCTE
    WHERE   [Date] <= @Enddate
)

INSERT INTO #Data
SELECT  MIN([Date]),
        COUNT(*) [Day]
FROM    DaysCTE
        LEFT JOIN HolidayTable
            ON [Date] BETWEEN HolStart AND HolEnd
WHERE   HolidayTypeID IS NULL
AND     DATENAME(WEEKDAY, [Date]) NOT IN ('Saturday', 'Sunday')
GROUP BY DATEPART(MONTH, [Date]), DATEPART(YEAR, [Date])
OPTION (MAXRECURSION 366)

DECLARE @Date DATETIME
SET @Date = (SELECT MIN(FirstDay) FROM #Data)

SELECT  Period,
        WorkingDays [Days Available (Minus the Holidays)]
FROM    (   SELECT  DATENAME(MONTH, Firstday) [Period],
                    WorkingDays,
                    0 [SortField],
                    FirstDay
            FROM    #Data
            UNION
            SELECT  DATENAME(MONTH, @Date) + ' - ' + DATENAME(MONTH, Firstday),
                    (   SELECT  SUM(WorkingDays)
                        FROM    #Data b
                        WHERE   b.FirstDay <= a.FirstDay
                    ) [WorkingDays],
                    1 [SortField],
                    FirstDay 
            FROM    #Data a
            WHERE   FirstDay > @Date
        ) data
ORDER BY SortField, FirstDay

DROP TABLE #Data

如果你这样做了1年多,你需要更改线路:

OPTION (MAXRECURSION 366)

否则,你会得到一个错误 - 的数量需要比你要查询的天数较高。


编辑

我刚刚参加翻过我这个老答案,真的不喜欢它,还有,我现在考虑的做法不好,所以我要纠正的所有问题,这么多东西:

  1. 我没有用分号结束语句正确
  2. 使用递归CTE生成日期列表
    • 生成离不开循环一组或序列-第1部分
    • 生成离不开循环一组或序列-第2部分
    • 生成离不开循环一组或序列-第3部分
  3. 不包括对插入的列列表
  4. 二手DATENAME到elimiate周末,这是语言特定的,更好的明确设定DATEFIRST和使用DATEPART
  5. 使用LEFT JOIN/IS NULL代替NOT EXISTS从假期表elimiate记录。 在SQL Server LEFT JOIN / IS NULL比NOT EXISTS效率较低

这些都是小事情,但他们的东西检讨别人的查询时,我会批评(至少在我的头上,如果不是念Wo),所以不能真的不纠正我自己的工作! 将查询重写会给。

SET DATEFIRST 1;

DECLARE @StartDate DATETIME = '20110401',
        @EndDate DATETIME = '20120331';

CREATE TABLE #Data (FirstDay DATETIME NOT NULL PRIMARY KEY, WorkingDays INT NOT NULL);

WITH DaysCTE ([Date]) AS
(   SELECT  TOP (DATEDIFF(DAY, @StartDate, @EndDate) + 1)
            DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @StartDate)
    FROM    sys.all_objects a
)
INSERT INTO #Data (FirstDay, WorkingDays)
SELECT  FirstDay =  MIN([Date]),
        WorkingDays = COUNT(*) 
FROM    DaysCTE d
WHERE   DATEPART(WEEKDAY, [Date]) NOT IN (6, 7)
AND     NOT EXISTS
        (   SELECT  1
            FROM    dbo.HolidayTable ht
            WHERE   d.[Date] BETWEEN ht.HolStart AND ht.HolEnd
        )
GROUP BY DATEPART(MONTH, [Date]), DATEPART(YEAR, [Date]);

DECLARE @Date DATETIME = (SELECT MIN(FirstDay) FROM #Data);

SELECT  Period,
        [Days Available (Minus the Holidays)] = WorkingDays 
FROM    (   SELECT  DATENAME(MONTH, Firstday) [Period],
                    WorkingDays,
                    0 [SortField],
                    FirstDay
            FROM    #Data
            UNION
            SELECT  DATENAME(MONTH, @Date) + ' - ' + DATENAME(MONTH, Firstday),
                    (   SELECT  SUM(WorkingDays)
                        FROM    #Data b
                        WHERE   b.FirstDay <= a.FirstDay
                    ) [WorkingDays],
                    1 [SortField],
                    FirstDay 
            FROM    #Data a
            WHERE   FirstDay > @Date
        ) data
ORDER BY SortField, FirstDay;

DROP TABLE #Data;

作为最后一点,这个查询成为一个更加简单的日历表 ,存储所有日期,并具有标志为工作日,节假日等,而不是使用只是存储假期假期表。



Answer 2:

让我几毛钱到这个职位。 刚分配来计算计划时间和实际时间之间的差异。 下面的代码被转换为函数。 到目前为止,尚无任何与逻辑问题:

declare @date datetime = '11/07/2012'
declare @t table (HolidayID int IDENTITY(1,1) primary key,
    HolidayYear int,
    HolidayName varchar(50),
    HolidayDate datetime)

INSERT @t
VALUES(2012, 'New Years Day', '01/02/2012'),
(2012,'Martin Luther King Day', '01/16/2012'),
(2012,'Presidents Day', '02/20/2012'),
(2012,'Memorial Day', '05/28/2012'),
(2012,'Independence Day', '07/04/2012'),
(2012,'Labor Day', '09/03/2012'),
(2012,'Thanksgiving Day', '11/22/2012'),
(2012,'Day After Thanksgiving', '11/23/2012'),
(2012,'Christmas Eve', '12/24/2012'),
(2012,'Christmas Day', '12/25/2012'),
(2013, 'New Years Day', '01/01/2013'),
(2013,'Martin Luther King Day', '01/21/2013'),
(2013,'Presidents Day', '02/18/2013'),
(2013,'Good Friday', '03/29/2013'),
(2013,'Memorial Day', '05/27/2013'),
(2013,'Independence Day', '07/04/2013'),
(2013,'Day After Independence Day', '07/05/2013'),
(2013,'Labor Day', '09/02/2013'),
(2013,'Thanksgiving Day', '11/28/2013'),
(2013,'Day After Thanksgiving', '11/29/2013'),
(2013,'Christmas Eve', NULL),
(2013,'Christmas Day', '12/25/2013')


DECLARE @START_DATE DATETIME, 
    @END_DATE DATETIME, 
    @Days int

SELECT  @START_DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, @date), 0) 

SELECT  @END_DATE = DATEADD(month, 1,@START_DATE)

;WITH CTE AS
(
    SELECT DATEADD(DAY, number, (DATEADD(MONTH, DATEDIFF(MONTH, 0, @date), 0) )) CDate
    FROM master.dbo.spt_values where type = 'p' and number between 0 and 365
        EXCEPT
    SELECT HolidayDate FROM @t WHERE HolidayYear = YEAR(@START_DATE) 
)
SELECT @Days = COUNT(CDate) --, datepart(dw, CDate) WDay
FROM CTE 
WHERE (CDate >=@START_DATE and CDate < @END_DATE) AND DATEPART(dw, CDate) NOT IN(1,7)

SELECT @Days 


文章来源: SQL populate total working days per month minus bank holidays for current financial year