Proszę, proszę, użyj tabeli kalendarza. SQL Server nie wie nic o świętach państwowych, wydarzeniach firmowych, klęskach żywiołowych itp. Tabela kalendarza jest dość łatwa do zbudowania, zajmuje bardzo mało miejsca i będzie znajdować się w pamięci, jeśli jest do niej wystarczająco odwołana.
Oto przykład, który tworzy tabelę kalendarza z 30-letnimi datami (2000 -> 2029), ale wymaga tylko 200 KB na dysku (136 KB w przypadku kompresji strony). Jest to prawie gwarantowane, że jest to mniej niż przydział pamięci wymagany do przetworzenia niektórych CTE lub innych ustawionych w czasie wykonywania.
CREATE TABLE dbo.Calendar
(
dt DATE PRIMARY KEY, -- use SMALLDATETIME if < SQL Server 2008
IsWorkDay BIT
);
DECLARE @s DATE, @e DATE;
SELECT @s = '2000-01-01' , @e = '2029-12-31';
INSERT dbo.Calendar(dt, IsWorkDay)
SELECT DATEADD(DAY, n-1, '2000-01-01'), 1
FROM
(
SELECT TOP (DATEDIFF(DAY, @s, @e)+1) ROW_NUMBER()
OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS x(n);
SET DATEFIRST 1;
-- weekends
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE DATEPART(WEEKDAY, dt) IN (6,7);
-- Christmas
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE MONTH(dt) = 12
AND DAY(dt) = 25
AND IsWorkDay = 1;
-- continue with other holidays, known company events, etc.
Teraz zapytanie, którego szukasz, jest dość proste do napisania:
SELECT COUNT(*) FROM dbo.Calendar
WHERE dt >= '20130110'
AND dt < '20130115'
AND IsWorkDay = 1;
Więcej informacji o tabelach kalendarza:
http://web.archive.org/web/20070611150639/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.html
Więcej informacji o generowaniu zestawów bez pętli:
http://www.sqlperformance.com/tag/date-ranges
Uważaj również na drobiazgi, takie jak poleganie na angielskim danych wyjściowych DATENAME
. Widziałem kilka aplikacji, które przestały działać, ponieważ niektórzy użytkownicy mieli inne ustawienia języka, a jeśli polegasz na WEEKDAY
upewnij się, że ustawiłeś DATEFIRST
ustawienie odpowiednio...