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)
プレ>そうしないと、エラーが発生します - 数は、クエリしている日数よりも大きくする必要があります。
編集
私はちょうど私のこの古い答えに出くわしましたが、本当にそれが好きではありません。今では悪い習慣だと考えることがたくさんあるので、すべての問題を修正します:
<オール>
DATEFIRST
を明示的に設定する方がはるかに優れています。 DATEPART
を使用します 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;
プレ>最後のポイントとして、このクエリは カレンダー テーブル 休日だけを格納する休日テーブルを使用するのではなく、すべての日付を格納し、営業日、休日などのフラグを持っています。