Next Available Date
Saw a post the other day on SQLTeam.
The OP Asked: "If I supply a Date, How can I get the next available date, that is not a holiday, and is not on the weekend."
I came up with this hack...please let me know if anyone has come with a different version
Thanks
Brett
CREATE TABLE Holidays (Holiday_Dt datetime, HoldayName varchar(255))
GO
INSERT INTO Holidays(Holiday_Dt, HoldayName)
SELECT '1/1/2010', 'New Years Day' UNION ALL
SELECT '1/18/2010', 'Martin Luther King' UNION ALL
SELECT '2/15/2010', 'President''s Day' UNION ALL
SELECT '5/31/2010', 'Memorial Day' UNION ALL
SELECT '7/5/2010', 'July 4th Holiday' UNION ALL
SELECT '9/6/2010', 'Labor Day' UNION ALL
SELECT '11/25/2010', 'Thanksgiving' UNION ALL
SELECT '11/26/2010', 'Black Friday' UNION ALL
SELECT '12/24/2010', 'Christmas Holiday' UNION ALL
SELECT '12/31/2010', 'New Years Eve'
GO
DECLARE @inp_Dt datetime; SET @inp_Dt = '11/25/2010'
SELECT TOP 1 CASE WHEN Holiday_Dt IS NULL THEN inp_Dt ELSE DATEADD(d,n,inp_Dt) END AS Next_Available_Dt
FROM (SELECT @inp_Dt AS inp_Dt) AS XXX
LEFT JOIN Holidays h
ON h.Holiday_Dt = xxx.inp_Dt
LEFT JOIN (SELECT 1 n UNION SELECT 2 n UNION SELECT 3 n UNION SELECT 4 n UNION
SELECT 5 n UNION SELECT 6 n UNION SELECT 7 n) AS n
ON xxx.inp_Dt < DATEADD(d,n,inp_Dt)
WHERE DATENAME(dw,DATEADD(d,n,inp_Dt)) NOT IN ('Saturday','Sunday')
AND NOT EXISTS (SELECT * FROM Holidays WHERE Holiday_Dt = DATEADD(d,n,inp_Dt))
GO
DROP TABLE Holidays
GO
Legacy Comments
Milan
2010-06-30 |
re: Next Available Date Hi, this is similar - just query plan seems to me better :) SELECT TOP 1 z.* FROM ( SELECT x = DATEADD(d, n.n, @inp_Dt) FROM (SELECT 1 n UNION SELECT 2 n UNION SELECT 3 n UNION SELECT 4 n UNION SELECT 5 n UNION SELECT 6 n UNION SELECT 7 n) AS n WHERE DATENAME(dw, DATEADD(d, n.n, @inp_Dt)) NOT IN ('Saturday','Sunday') ) z WHERE NOT EXISTS (SELECT * FROM Holidays WHERE Holiday_Dt = z.x) Best regards, Milan |
Rob Volk
2010-06-30 |
re: Next Available Date Here's 2 variations on the last option using CTE's: ;with a(n) as (select 1 union all select 0 union all select 0), b(n) as (select 0 from a cross join a b), c(Date) as (select DateAdd(day, ROW_NUMBER() over (order by n), @inp_dt) from b ) select top 1 * from c c where DATENAME(dw,c.date) not in ('Saturday','Sunday') and not exists(select * from Holidays where Holiday_Dt = c.Date) ;with a(n) as (select 1 union all select n+1 from a where n<7), d(Date) as (select DateAdd(day, n, @inp_dt) from a ) select top 1 * from d d where DATENAME(dw,d.date) not in ('Saturday','Sunday') and not exists(select * from Holidays where Holiday_Dt = d.Date) Both have simpler plans but their execution times are the same or slightly worse than Milan's, at least on my server. One nice suggestion is to use the CTE in a view definition for generic numbers, and possibly add generic dates as well, and then this query (and others like it) are simple SELECTs against that view. |
Peso
2010-07-01 |
re: Next Available Date DATENAME is culture dependant so the suggesetions abov won't work in other language than english. Anyhows, here is my suggestion SELECT TOP(1) i.theDate AS Next_Available_Dt FROM ( SELECT DATEADD(DAY, number, @inp_Dt) FROM master.dbo.spt_values WHERE Type = 'P' AND DATEDIFF(DAY, 0, DATEADD(DAY, number, @inp_Dt)) % 7 < 5 ) AS i(theDate) LEFT JOIN dbo.Holidays AS h ON h.Holiday_Dt = i.theDate WHERE h.Holiday_Dt IS NULL ORDER BY i.theDate |