Snälla, snälla, använd en kalendertabell. SQL Server vet ingenting om nationella helgdagar, företagsevenemang, naturkatastrofer, etc. En kalendertabell är ganska enkel att bygga, tar extremt lite utrymme och kommer att finnas i minnet om det finns tillräckligt med referenser.
Här är ett exempel som skapar en kalendertabell med 30 års datum (2000 -> 2029) men som bara kräver 200 KB på disk (136 KB om du använder sidkomprimering). Det är nästan garanterat mindre än minnesanslaget som krävs för att bearbeta någon CTE eller annan uppsättning vid körning.
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.
Nu är frågan du letar efter ganska enkel att skriva:
SELECT COUNT(*) FROM dbo.Calendar
WHERE dt >= '20130110'
AND dt < '20130115'
AND IsWorkDay = 1;
Mer information om kalendertabeller:
http://web.archive.org/web/20070611150639/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.html
Mer information om generatoraggregat utan loopar:
http://www.sqlperformance.com/tag/date-ranges
Akta dig också för små saker som att lita på den engelska utdata av DATENAME
. Jag har sett flera applikationer gå sönder eftersom vissa användare hade en annan språkinställning, och om du förlitar dig på WEEKDAY
se till att du ställer in din DATEFIRST
inställning på rätt sätt...