SQL填充每月总工作日减去当前财政年度的银行假日

Jso*_*ham 0 sql sql-server date sql-server-2008 reporting-services

我正在查看一个看起来像我的第一张附图,但右侧列填充而不是空白.逻辑如下:

数据必须是当前财务期.4月将是2011年,3月将是2012年等等.

单个月的可用天数计算如下:

工作日总数(星期一至星期五)减去该特定财政年度的特定月份的银行假日(我们保存在表格中 - 见第二张图片).

节日表的列名左至右:holidaytypeid,名称,holstart,holend.表名:假期

为了计算累计月份的"可用天数",将对单个月的已填充数据进行求和.例如,4月至5月的数据将是4月和5月的数据,以此类推.

我需要完美格式的SQL查询,以便可以直接粘贴并且可以工作(即使用正确的列名和表名)

谢谢你的期待.

在此输入图像描述

在此输入图像描述

Gar*_*thD 6

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
Run Code Online (Sandbox Code Playgroud)

如果您执行此操作超过1年,则需要更改该行:

OPTION (MAXRECURSION 366)
Run Code Online (Sandbox Code Playgroud)

否则您将收到错误 - 该数字需要高于您查询的天数.


编辑

我刚刚接受了我的这个老答案,真的不喜欢它,有很多东西我现在认为是不好的做法,所以我要纠正所有的问题:

  1. 我没有正确地用半冒号终止语句
  2. 使用递归CTE生成日期列表
  3. 没有包含插入的列列表
  4. 使用DATENAME来消除特定于语言的周末,​​更好地明确设置DATEFIRST和使用DATEPART
  5. 用于LEFT JOIN/IS NULL代替NOT EXISTS从假日表中删除记录.在SQL Server中LEFT JOIN/IS NULL效率低于NOT EXISTS

这些都是微不足道的事情,但是在审查别人的查询时,我会批评(至少在我的头脑中,如果不是在外面),所以不能真正纠正我自己的工作!重写查询会给.

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;
Run Code Online (Sandbox Code Playgroud)

最后一点,使用存储所有日期的日历表,并且具有工作日,假日等标志,而不是使用仅存储假期的假日表,此查询变得更加简单.