Author |
Topic |
sotian
Starting Member
8 Posts |
Posted - 2007-02-27 : 05:02:05
|
Hello,I'm using SQL Server 2000.I wonder if anyone can help, I have a header record, and sub records. The sub records have a date.I'm looking for an efficient way of returning header id's that have a close density of dates within a larger date range. The density is defined as n dates or more in d days - this can vary.e.g for 3 dates in 5 days:01 Jan 200705 Jan 200708 Jan 200712 Jan 200718 Jan 200720 Jan 200729 Jan 2007So i'm not interested in this one there isn't any three dates within 5 days.But for his one08 Jan 200720 Jan 200721 Jan 200722 Jan 200723 Jan 200702 Feb 2007I'm interested in this Header ID, there are actually 4 within the 5 days window between 20 - 23 Jan.Note there could be hundreds of dates per header, and 100,000's of header records. So processing this by looping around with a cursor will probably be very slow.I'm guessing there isn't an easy way to do this. The data will be moved across to .NET at some point, but if I could get a small a list as possible from SQL that would be great.If the density definition was fixed I could store a list of them as the records were written, however it can vary.Is there a way of detecting densities withing SQL server. If not, does anyone have any suggestions?Thanks,Jon |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-02-27 : 05:06:19
|
Which records do you want for these sample data?08 Jan 200720 Jan 200721 Jan 200722 Jan 200723 Jan 200702 Feb 2007---------------------------1) 20-22 Jan 2007 (20, 21 or 22)2) 21-23 Jan 2007 (21, 22 or 23)Peter LarssonHelsingborg, Sweden |
 |
|
sotian
Starting Member
8 Posts |
Posted - 2007-02-27 : 05:10:09
|
I don't mind if this returns the header id once or twice really. The fact there is at least one group of three is good enough to return the header id.Thanks,Jonquote: Originally posted by Peso Which records do you want for these sample data?08 Jan 200720 Jan 200721 Jan 200722 Jan 200723 Jan 200702 Feb 2007---------------------------1) 20-22 Jan 2007 (20, 21 or 22)2) 21-23 Jan 2007 (21, 22 or 23)Peter LarssonHelsingborg, Sweden
|
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-02-27 : 05:12:48
|
[code]-- prepare sample datadeclare @t table (dt datetime)insert @tselect '08 Jan 2007' union allselect '20 Jan 2007' union allselect '21 Jan 2007' union allselect '22 Jan 2007' union allselect '23 Jan 2007' union allselect '02 Feb 2007'-- Example 1SELECT t1.dtFROM @t AS t1INNER JOIN @t AS t2 ON t2.dt BETWEEN t1.dt - 2 AND t1.dt + 2GROUP BY t1.dtHAVING COUNT(t2.dt) > 2-- Example 2SELECT t1.dt AS FromDate, t1.dt + 2 AS ToDateFROM @t AS t1INNER JOIN @t AS t2 ON t2.dt BETWEEN t1.dt AND t1.dt + 2GROUP BY t1.dtHAVING COUNT(t2.dt) > 2[/code]Peter LarssonHelsingborg, Sweden |
 |
|
sotian
Starting Member
8 Posts |
Posted - 2007-02-27 : 05:34:34
|
Hello,Thanks for your reply, that looks good. How would I adapt this to say look for 3 calls within 30 days for example:02-Jan-200701-Feb-200710-Feb-200729-Feb-200718-Mar-2007Returning 01-Feb-2007 - 29-Feb-2007Thanks,Jon |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-02-27 : 05:44:45
|
Is 29th of February 2007 available?Peter LarssonHelsingborg, Sweden |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-02-27 : 05:46:50
|
[code]-- prepare sample datadeclare @t table (dt datetime)insert @tselect '02-Jan-2007' union allselect '01-Feb-2007' union allselect '10-Feb-2007' union allselect '28-Feb-2007' union allselect '18-Mar-2007'-- ExampleSELECT t1.dt AS FromDate, t1.dt + 30 AS ToDateFROM @t AS t1INNER JOIN @t AS t2 ON t2.dt BETWEEN t1.dt AND t1.dt + 30GROUP BY t1.dtHAVING COUNT(t2.dt) > 2[/code]Peter LarssonHelsingborg, Sweden |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-02-27 : 05:48:08
|
More generic...-- prepare sample datadeclare @t table (dt datetime)insert @tselect '02-Jan-2007' union allselect '01-Feb-2007' union allselect '10-Feb-2007' union allselect '28-Feb-2007' union allselect '18-Mar-2007'DECLARE @DaysRange INT, @NumOfCalls INTSELECT @DaysRange = 30, @NumOfCalls = 3SELECT t1.dt AS FromDate, t1.dt + @DaysRange AS ToDateFROM @t AS t1INNER JOIN @t AS t2 ON t2.dt BETWEEN t1.dt AND t1.dt + @DaysRangeGROUP BY t1.dtHAVING COUNT(t2.dt) >= @NumOfCalls Peter LarssonHelsingborg, Sweden |
 |
|
sotian
Starting Member
8 Posts |
Posted - 2007-02-27 : 05:54:04
|
Peter,Wow that's fantastic, your a genius thanks, I'll have to use those recursive joins in the future when I get my head fully around them. There are few situations in the past where they would have been useful.Thanks,Jon |
 |
|
harsh_athalye
Master Smack Fu Yak Hacker
5581 Posts |
Posted - 2007-02-27 : 06:10:38
|
"I'll have to use those recursive joins in the future when I get my head fully around them"SELF-JOIN is the more appropriate term !Harsh AthalyeIndia."The IMPOSSIBLE is often UNTRIED" |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-02-27 : 06:25:51
|
Thank you.I call them SELF JOINs, not recursive JOINs.If your columns also include TIME information, you can use this-- prepare sample datadeclare @t table (dt datetime)insert @tselect '02-Jan-2007' union allselect '01-Feb-2007' union allselect '10-Feb-2007' union allselect '28-Feb-2007' union allselect '18-Mar-2007'DECLARE @DaysRange INT, @NumOfCalls INTSELECT @DaysRange = 35, @NumOfCalls = 4SELECT t1.dt AS theDateFROM @t AS t1CROSS JOIN @t AS t2WHERE t2.dt >= DATEADD(day, DATEDIFF(day, 0, t1.dt), 0) AND t2.dt < DATEADD(day, DATEDIFF(day, 0, t1.dt), @DaysRange) OR t2.dt >= DATEADD(day, DATEDIFF(day, @DaysRange, t1.dt), 1) AND t2.dt < DATEADD(day, DATEDIFF(day, 0, t1.dt), 1)GROUP BY t1.dtHAVING COUNT(*) >= @NumOfCalls If unsure, look for "Operator Precedence" in Books OnlinePeter LarssonHelsingborg, Sweden |
 |
|
sotian
Starting Member
8 Posts |
Posted - 2007-02-27 : 09:18:53
|
So Does the original version not work with times? Why is that? |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-02-27 : 12:23:11
|
When you add a number of days to a datetime, the new date has same time as original datetime.And if you want to make sure all times for certain date are included, that is 00:00:00.000 to 23:59:59.997, it is not enough to just add a number of days to calculate, because the original date might have the time 15:15:15.467 as an example.Peter LarssonHelsingborg, Sweden |
 |
|
sotian
Starting Member
8 Posts |
Posted - 2007-02-28 : 04:00:50
|
Ah I understand, however thats not a big deal.The solution is implemented works well, and is very fast.Thanks,Jonquote: Originally posted by Peso When you add a number of days to a datetime, the new date has same time as original datetime.And if you want to make sure all times for certain date are included, that is 00:00:00.000 to 23:59:59.997, it is not enough to just add a number of days to calculate, because the original date might have the time 15:15:15.467 as an example.Peter LarssonHelsingborg, Sweden
|
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-02-28 : 04:19:52
|
Great!Try this. I believe this is even faster.-- prepare sample datadeclare @t table (dt datetime)insert @tselect '02-Jan-2007' union allselect '01-Feb-2007' union allselect '10-Feb-2007' union allselect '28-Feb-2007' union allselect '18-Mar-2007'-- Initialize searchDECLARE @DaysRange INT, @NumOfCalls INTSELECT @DaysRange = 35, @NumOfCalls = 4SELECT t1.dt AS theDateFROM @t AS t1CROSS JOIN @t AS t2WHERE t2.dt BETWEEN t1.dt - @DaysRange AND t1.dt + @DaysRangeGROUP BY t1.dtHAVING COUNT(*) >= @NumOfCalls Peter LarssonHelsingborg, Sweden |
 |
|
|