| Author |
Topic |
|
igorblackbelt
Constraint Violating Yak Guru
407 Posts |
Posted - 2006-06-27 : 14:17:35
|
| Hey All -I'm trying to update a column, whenever the day falls on a sat, sun or holiday, the field needs to be adjusted to the next business day, can you guys point me to the right direction ?Should I make use of Stored Procedures or UDF ?Thanks!---Thanks!Igor. |
|
|
DonAtWork
Master Smack Fu Yak Hacker
2167 Posts |
|
|
cvraghu
Posting Yak Master
187 Posts |
Posted - 2006-06-27 : 16:36:48
|
| I assume that you've a table storing holiday list - update table1set businessday = case when lower(datename(dw,table1.businessday)) = 'saturday' then dateadd(dd,2,table1.businessday) when lower(datename(dw,table1.businessday)) = 'sunday' then dateadd(dd,1,table1.businessday) when lower(datename(dw,table1.businessday)) = 'friday' and exists (select 'x' from holidays where holiday = table1.businessday) then dateadd(dd,3,table1.businessday) when exists (select 'x' from holidays where holiday = table1.businessday) then dateadd(dd,1,table1.businessday) end |
 |
|
|
cvraghu
Posting Yak Master
187 Posts |
Posted - 2006-06-27 : 16:47:32
|
| The logic to arrive at the no of days to be added is not correct in the query. It does not consider the fact that it could be a holiday. But you can think in these lines. |
 |
|
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2006-06-27 : 16:58:47
|
| Igor,Do you have a date table, with holidays?It would make things so much simpler.I would consider the following options as well (not udf,sp)1. Have a view that returns the date and the nextWorkDayDate2. Have a trigger on the table that adjusts the data.In 2) I would seriously consider storing the original date, and a column storing the calculated workDayDate as well.3. A calculated column for the workDayDate, (similar solution to 2.)rockmoose |
 |
|
|
cvraghu
Posting Yak Master
187 Posts |
Posted - 2006-06-27 : 18:54:21
|
| You can make use of this recursive function - create function getNextBusinessDay(@iDate datetime) returns datetimeasbegin declare @ODate datetime select @ODate = case when lower(datename(dw,@iDate)) = 'saturday' then dateadd(dd,2,@iDate) when lower(datename(dw,@iDate)) = 'sunday' then dateadd(dd,1,@iDate) when lower(datename(dw,@iDate)) = 'friday' and exists (select 'x' from holidays where holiday = @iDate) then dateadd(dd,3,@iDate) when exists (select 'x' from holidays where holiday = @iDate) then dateadd(dd,1,@iDate) else @iDate end If Exists(Select 'X' from holidays where holiday = @ODate) Select @ODate = dbo.getNextBusinessDay(@ODate) return @ODateendupdate table1set businessday = dbo.getNextBusinessDay(businessday)If you want to update only the needed rows, make modifications to function and update statement as needed. |
 |
|
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2006-06-27 : 20:47:20
|
The update is fairly easy if you have a table of Work Days.The code shows how to load the Work Days table from a Date table and and Holiday table.The Date Table Function F_TABLE_DATE is available here:http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=61519-- Select date range for updatedeclare @start_date datetimedeclare @end_date datetime-- 20 Days before todayselect @start_date = dateadd(dd,datediff(dd,0, getdate()-20),0)-- 40 Days after start dateselect @end_date = @start_date+40select [@start_date] = convert(varchar(10),@start_date,121), [ @end_date] = convert(varchar(10),@end_date,121)-- Holiday tabledeclare @holiday table ([DATE] datetime not null primary key clustered )print '*** Load @holiday'insert into @holidayselect '20060704' -- July 4th Holiday-- Work Date Tabledeclare @WorkDate table ([WORK_DATE] datetime not null primary key clustered )print '*** Load @WorkDate'-- Load table with Work Daysinsert into @WorkDateselect a.[DATE]from -- Date Table Function from Script Library dbo.F_TABLE_DATE ( @start_date,@end_date) a left join @holiday b on a.[DATE] = b.[DATE]where -- Select Monday through Friday a.[DAY_OF_WEEK] between 2 and 6 and -- Exclude Holidays b.[DATE] is null-- Test Datadeclare @MyTable table (MyTableID int identity(1,1) primary key clustered,MyDate datetime not null)print '*** Load @MyTable'-- Load test dates to be updatedinsert into @MyTable (MyDate)select '20060623' union allselect '20060624' union allselect '20060625' union allselect '20060626' union allselect '20060627' union allselect '20060628' union allselect '20060704'print '*** @MyTable before update'select * from @MyTableprint '*** Update @MyTable'update aset a.MyDate = ( -- Update to earliest work date > MyDate select [DATE] = min(c.[WORK_DATE]) from @WorkDate c where c.[WORK_DATE] > a.MyDate )from @MyTable awhere -- Select only dates in ramge a.MyDate >= @start_date and a.MyDate < (select max(z.[WORK_DATE]) from @WorkDate z ) and -- Select rows that are not work days a.MyDate not in ( select x.[WORK_DATE] from @WorkDate x )print '*** @MyTable after update'select * from @MyTable Results:start_date @end_date ----------- ---------- 2006-06-07 2006-07-17(1 row(s) affected)*** Load @holiday(1 row(s) affected)*** Load @WorkDate(28 row(s) affected)*** Load @MyTable(7 row(s) affected)*** @MyTable before updateMyTableID MyDate ----------- ------------------------------------------------------ 1 2006-06-23 00:00:00.0002 2006-06-24 00:00:00.0003 2006-06-25 00:00:00.0004 2006-06-26 00:00:00.0005 2006-06-27 00:00:00.0006 2006-06-28 00:00:00.0007 2006-07-04 00:00:00.000(7 row(s) affected)*** Update @MyTable(3 row(s) affected)*** @MyTable after updateMyTableID MyDate ----------- ------------------------------------------------------ 1 2006-06-23 00:00:00.0002 2006-06-26 00:00:00.0003 2006-06-26 00:00:00.0004 2006-06-26 00:00:00.0005 2006-06-27 00:00:00.0006 2006-06-28 00:00:00.0007 2006-07-05 00:00:00.000(7 row(s) affected) CODO ERGO SUM |
 |
|
|
rob_farley
Yak Posting Veteran
64 Posts |
Posted - 2006-06-27 : 21:34:51
|
| I feel like you're over-complicating things, which would be much simpler with an auxiliary table of numbers (a table of numbers from 0 up to some arbitrary number - I call my table 'nums', with a single int column 'num').--First make sure you have a holidays table:select '4-jul-2006' holiday_date into dbo.holidays;insert into holidays values ('3-jul-2006');--Then create your functioncreate function dbo.uf_nextbusinessday(@today datetime) returns datetime asbegin declare @res datetime declare @today_trunc datetime --First truncate the date set @today_trunc = cast(floor(cast(@today as float)) as datetime) --Now find the first day which isn't either Saturday, Sunday, or a holiday select @res = min(d.candidate) from (select dateadd(day,n.num,@today_trunc) candidate from nums n where n.num < 7) d left join holidays h on h.holiday_date = d.candidate where h.holiday_date is null and datepart(dw,d.candidate) not in (6,7) return (@res)end--If you try populating a table of holidays with Jul 3rd and 4th, then this query should demonstrate success or not:select d.theday, dbo.uf_nextbusinessday(d.theday) thebusinessdayfrom(select dateadd(day,n.num,'1-jun-2006') theday from nums n where n.num < 40) dI hope this helps...RobRob Farleyhttp://robfarley.blogspot.com |
 |
|
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2006-06-27 : 22:29:42
|
Rob, your computer must have a non-US setting, because 6 and 7 are not both weekend days under US settings, unless you consider Friday a weekend day.This is why I do not like using functions that depend on a particular setting of DATEFIRST to return correct results.select DT = convert(varchar(10), DT,121), DW = datepart(dw,dt), DName= datename(dw,DT)from (select DT = getdate()+4 union all select DT = getdate()+3) aResults:DT DW DName ---------- ----------- ------------------------------ 2006-07-01 7 Saturday2006-06-30 6 Friday(2 row(s) affected) CODO ERGO SUM |
 |
|
|
byrmol
Shed Building SQL Farmer
1591 Posts |
Posted - 2006-06-27 : 22:43:35
|
| >>....unless you consider Friday a weekend day.Rob's an Aussie Michael, so when the the surf's up and the sun is hot, everyday is the weekend...DavidMIntelligent Design is NOT science.A front-end is something that tries to violate a back-end. |
 |
|
|
rob_farley
Yak Posting Veteran
64 Posts |
Posted - 2006-06-27 : 22:44:35
|
| Ah - yes... I'm in Australia, where many calendars start on Mondays.So use this instead:and (datepart(dw,d.candidate) + @@datefirst)%7 not in (0,1)--replaces: and datepart(dw,d.candidate) not in (6,7)Rob Farleyhttp://robfarley.blogspot.com |
 |
|
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2006-06-28 : 03:39:53
|
quote: Originally posted by byrmol >>....unless you consider Friday a weekend day.Rob's an Aussie Michael, so when the the surf's up and the sun is hot, everyday is the weekend...DavidM
Seems I was born on the wrong side of the globe rockmoose |
 |
|
|
rob_farley
Yak Posting Veteran
64 Posts |
Posted - 2006-06-28 : 03:42:09
|
| :) I wasn't born here. And I'm English on the inside.Rob Farleyhttp://robfarley.blogspot.com |
 |
|
|
igorblackbelt
Constraint Violating Yak Guru
407 Posts |
Posted - 2006-07-05 : 11:56:50
|
| wow guys, I guess I forgot this topic hehe, I used a function that I found on SQLServerCentral, and that's been working pretty well, I'll review every and each post from you guys to see if that works better on my scenario, thanks for the replies.Here's the link to the UDF I spoke about:http://www.sqlservercentral.com/columnists/rScholl/findingthenextbusinessdayrecursively.aspAnd aswering to some of the questions, yes, I do have a Holidays table.---Thanks!Igor. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
|
|
|