January 6, 2011 at 8:27 pm
Rehman Rafique (1/6/2011)
Hey jeff, thnx for ur critical view on my code. it runs fine, i have tested it but it works for on equipment....just wanted to try another way to solve it....thou it can b modified accordinglyanyway thnx mayn.....Cheers
Heh... While loops don't usually "run fine", Rehman. They normally just run slow. Take a look at the following article to see what I mean... mayn... 😉
http://www.sqlservercentral.com/articles/T-SQL/62867/
--Jeff Moden
Change is inevitable... Change for the better is not.
January 6, 2011 at 10:25 pm
ok ill check it out.....
with "runs fine" i meant dat it provides da required result, i wasnt pointing towards it's execution time etc...
January 6, 2011 at 11:08 pm
Rehman Rafique (1/6/2011)
ok ill check it out.....with "runs fine" i meant dat it provides da required result, i wasnt pointing towards it's execution time etc...
Understood and appreciated. Since you're a bit new to this forum, I just thought I'd let you know that most WHILE loop solutions are pretty much jumped on because of their general performance problems.
--Jeff Moden
Change is inevitable... Change for the better is not.
January 7, 2011 at 5:42 am
thnx jeff..... much appreciated!!!
January 7, 2011 at 12:02 pm
Thanks very much who has contributed to this thread. I really appreciate it.
Cheers,
...
XML DB Java Developer
'enthusiastic about software solutions for real life'
January 9, 2011 at 9:17 am
Using an in-line Table Function to split the time.
Go
If object_id('SplitTimeCrossingMidnight') is not null Drop Function SplitTimeCrossingMidnight
Go
Create Function SplitTimeCrossingMidnight(
@StartDateTime SmalldateTime,
@EndDateTime SmalldateTime
)
Returns Table
As
Return(
With DT as
(select
StartdateTime=@StartdateTime,
EndDateTime=Case when datediff(dd,@StartDateTime,@EndDateTime)=0
Then @EndDateTime
Else cast(dateadd(dd,datediff(dd,0,@StartDateTime)+1,0) as SmalldateTime) -- Midnight
End
Union all
Select
StartdateTime=EndDateTime,
EndDateTime=Case when datediff(dd,EndDateTime,@EndDateTime)=0
Then @EndDateTime
Else cast(dateadd(dd,datediff(dd,0,EndDateTime)+1,0) as SmalldateTime) -- Midnight
End
From DT
Where
EndDateTime<@EnddateTime
)
Select * from DT
)
Go
If Object_id('Tempdb..#MyTable') is Not Null Drop Table #MyTable
CREATE TABLE #MyTable (
equipment varchar(20) NOT NULL,
date_start datetime NOT NULL,
date_end datetime NOT NULL
)
INSERT INTO #MyTable (equipment, date_start, date_end)
SELECT 'equip1', '2009-11-29T06:00:00', '2009-12-01T18:30:00' UNION ALL
SELECT 'equip2', '2008-12-30T11:00:00', '2009-01-02T18:30:25' UNION ALL
SELECT 'equip3', '2008-05-21T11:15:00', '2008-05-21T22:45:00'
Select
equipment,
date_start =StartdateTime,
hours_per_day =DATEDIFF(mi,DT.StartdateTime,DT.EndDateTime)/60.0
From #MyTable MT
Cross Apply(
Select
StartdateTime,
EndDateTime
From dbo.SplitTimeCrossingMidnight(MT.date_start,MT.date_end)
) DT
January 9, 2011 at 5:08 pm
Although you can certainly do some clever things with recursive CTE's, I generally try to avoid them because they're so very expensive for CPU and other resources compared to things like Tally Table solutions and, sometimes, even While Loops. And, no... I don't expect anyone to take my word for it... here's a test using code from this thread...
--===== Build and populate the test table with some additional test data
-- to make the test last long enough to measure the differences
If Object_id('Tempdb..#MyTable') is Not Null Drop Table #MyTable
CREATE TABLE #MyTable (
equipment varchar(20) NOT NULL,
date_start datetime NOT NULL,
date_end datetime NOT NULL
)
;
INSERT INTO #MyTable (equipment, date_start, date_end)
SELECT 'equip1', '2009-11-28 00:00:00', '2009-11-29 05:15:00' UNION ALL
SELECT 'equip1', '2009-11-29 06:00:00', '2009-12-01 18:30:00' UNION ALL
SELECT 'equip2', '2008-12-30 11:00:00', '2009-01-02 18:30:25' UNION ALL
SELECT 'equip3', '2008-05-21 11:15:00', '2008-05-21 22:45:00' UNION ALL
SELECT 'equip4', '2000-01-01 00:00:00', '2010-01-01 00:00:00' UNION ALL
SELECT 'equip5', '2000-01-01 00:00:00', '2010-01-01 00:00:00' UNION ALL
SELECT 'equip6', '2000-01-01 00:00:00', '2010-01-01 00:00:00'
;
GO
--========================================================================
;
GO
--===== Andrew''s Tally Table Solution
;WITH ctePrep AS (
SELECT equipment, date_start, date_end,
DATEADD(day, DATEDIFF(day, 0, date_start), 0) AS date_base,
DATEDIFF(day, date_start, date_end) AS day_num
FROM #MyTable
)
SELECT
equipment,
CASE WHEN (T.N = 0) THEN
D.date_start
ELSE
DATEADD(day, T.N, date_base)
END AS date_start,
CAST (
CASE WHEN (D.day_num = 0) THEN
D.date_end - D.date_start
WHEN (T.N = 0) THEN
DATEADD(day, 1, D.date_base) - D.date_start
WHEN (T.N = D.day_num) THEN
D.date_end - DATEADD(day, D.day_num, D.date_base)
ELSE 1 END AS float
) * 24.0 AS hours_per_day
FROM ctePrep D
INNER JOIN dbo.Tally T ON (T.N BETWEEN 0 AND D.day_num)
ORDER BY equipment, date_start
;
GO 5
--========================================================================
;
GO
--===== Recursive CTE function solution
Select
equipment,
date_start =StartdateTime,
hours_per_day =DATEDIFF(mi,DT.StartdateTime,DT.EnddateTime)/60.0
From #MyTable MT
Cross Apply(
Select
StartdateTime,
EnddateTime
From dbo.SplitTimeCrossingMidnight(MT.date_start,MT.date_end)
) DT
OPTION(MAXRECURSION 0)
;
GO 5
Here're the results from SQL Profiler. Check out the CPU column.
--Jeff Moden
Change is inevitable... Change for the better is not.
January 10, 2011 at 5:58 am
Thanks Jeff for following this up.
--Andrew
Viewing 8 posts - 16 through 22 (of 22 total)
You must be logged in to reply to this topic. Login to reply