Reputation: 1332
I'm working with some rather poorly designed tables here, and changing the structure is more or less out of the question. So with that said, here's my question.
I need to join TableB.Date on TableA.Date, with a margin of about 5 minutes. In other words, the join can't rely on a perfect match.
So if the date in TableA is 2011-12-01 10:00:00.000
, the join would match a record in TableB where the date is, 2011-12-01 10:03:00.000
or 2011-12-01 09:59:00.000
or 2011-12-01 10:04:35.000
I came up with a little trick to allow a margin of difference of about 1 minute by casting the datetime as smalldatetime, which drops the second and millisecond from the datetime value. It works quite well, but I need a larger margin than that.
LEFT JOIN TableB ON CAST(TableA.SomeDate AS smalldatetime) = CAST(TableB.SomeDate AS smalldatetime)
The date column in TableB is the only linkage between data in the two tables, so I cannot filter the results within the WHERE clause. I realize this can potentially produce some inaccurate results, but because of how and when the data is stored, I shouldn't run into any issues.
Any suggestions?
Upvotes: 4
Views: 10648
Reputation: 5415
The problem with this is that you have to define the 5 minute margin more rigidly for SQL to work well. If you want to be fuzzier then SQL is the wrong language.
What if 2 results on tableA are within 5 minutes of each other? Do they both join to the same record on tableB? You then get duplicated records.
What you want to do is bin your datetimes into 5 minute buckets (or whatever you choose) using a round down/up plan. A pre-made lookup table is always a quick performing solution, that table would contain an index column of every minute of every day and another column with your agreed 5 minute buckets. This intermediate table could be used to join tableA to tableB.
i.e. The LookupTable (excuse the formatting!)
LookupTime __________ BucketTime
2013-01-01 14:56 _____ 2013-01-01 14:55
2013-01-01 14:57_____ 2013-01-01 14:55
2013-01-01 14:58_____ 2013-01-01 15:00
2013-01-01 14:59_____ 2013-01-01 15:00
You would join the tableA date to the LookupTime above. You would do a separate join to a second copy of the LookupTime table for tableB, Then join the two copies of the lookup table to each other on the BucketTime Field.
The tricky part is agreeing on the rounding you will use. I recommend "Round To Even" which smooths out the rounding up bias that comes with rounding digits 1-4 down and 5-9 up.
Upvotes: 1
Reputation: 432361
Try DATEDIFF to look for less then 300 seconds (minute boundary is zero seconds which will give incorrect results). For more accuracy it matter, use milliseconds < 300000
TableA
LEFT JOIN
TableB ON ABS(DATEDIFF(second, TableA.SomeDate, TableB.SomeDate)) < 300
Upvotes: 7
Reputation: 33153
Join formatted dates. Format them so that they either round to the nearest 5 minutes or round to the relevant time span. It will probably require a user defined function.
Upvotes: 0