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)
अन्यथा आपको एक त्रुटि मिलेगी - यह संख्या आपके द्वारा क्वेरी किए जा रहे दिनों की संख्या से अधिक होनी चाहिए।
संपादित करें
मैं अभी-अभी अपने इस पुराने उत्तर पर आया हूं और वास्तव में इसे पसंद नहीं करता, ऐसी बहुत सी चीजें हैं जिन्हें मैं अब बुरा अभ्यास मानता हूं, इसलिए मैं सभी मुद्दों को ठीक करने जा रहा हूं:
- मैंने इनके साथ बयानों को समाप्त नहीं किया एक अर्ध कोलन ठीक से
- तिथियों की सूची बनाने के लिए पुनरावर्ती CTE का उपयोग किया
- सम्मिलित करने के लिए कॉलम सूची को शामिल नहीं किया
- सप्ताहांत को समाप्त करने के लिए DATENAME का उपयोग किया, जो कि भाषा विशिष्ट है, स्पष्ट रूप से सेट करने के लिए बेहतर है
DATEFIRST
औरDATEPART
. का उपयोग करें - इस्तेमाल किया गया
LEFT JOIN/IS NULL
के बजायNOT EXISTS
हॉलिडे टेबल से रिकॉर्ड खत्म करने के लिए। एसक्यूएल सर्वर में 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;
अंतिम बिंदु के रूप में, यह क्वेरी कैलेंडर तालिका जो सभी तिथियों को संग्रहीत करता है, और छुट्टियों को संग्रहीत करने वाली अवकाश तालिका का उपयोग करने के बजाय कार्य दिवसों, छुट्टियों आदि के लिए झंडे रखता है।