views:

52

answers:

3

This one has bugged me for a while now. Recently when revisiting some code I wrote for a customer a few years ago I was wondering if there is a more elegant solution to the problem.

The customer stores all of their clients information including date of birth (date time field)

They run an extract every Monday that retrieves any customer whose birthday will fall within the following week.

I.e. if the extract was run on Monday Jan 1st, Customers whose birthday fell between (and including) Monday Jan 8th -> Sunday Jan 14th would be retrieved.

My solution was to use the Datepart(dy) function and calculate all upcoming birthdays based off the customers date of birth converted to day of year, adding some logic to include for the extract being run at the end of a year. The problem was that using Day of year throws results off by 1 day if the customer was born on a leap year and / or the extract is run on a leap-year after the 29th of Feb, so once again I had to add more logic so the procedure returned the expected results.

This seemed quite over-kill for what should be a simple task For simplicity let’s say the table 'customer' contains 4 fields, first name, last name, dob, and address.

Any suggestions on how to simplify this would really be appreciated

Wes

+3  A: 

Why not use DATEPART(wk) on this year's birthday?

SET DATEFIRST 1  -- Set first day of week to monday
SELECT * FROM customer
WHERE DATEPART(wk, DATEADD(yy, DATEPART(yy, GETDATE()) - DATEPART(yy, customer.dob), customer.dob)) = DATEPART(wk, GETDATE()) + 1

It selects all customers who's birthday's weeknumber is one greater than the current weeknumber.

Jappie
I like this solution... But what if we don't start off from Monday, but from Thursday. Oh, I see... :)
Denis Valeev
1. According to MS `SETDATE FIRST 1` is Sunday not Monday
Unreason
@Unreason: no, it is monday. See http://msdn.microsoft.com/en-us/library/ms181598.aspx
Jappie
2. DATEPART(wk, date) is a function that depends on the year and fluctuates; you should bring the birthday into current year for your comparison test to work
Unreason
@Unreason: I bring the birthday into current year, that's what the dateadd is for.
Jappie
@Jappie, sorry for wrong claim in my #1; http://msdn.microsoft.com/en-us/library/aa258265%28SQL.80%29.aspx threw me off
Unreason
This solution is elegant, but when it comes to the end of the year calculations it becomes ugly.
Denis Valeev
@Japple, sorry for #2, it was written before your edit... this way it seems to be ok
Unreason
@Unreason, sorry, didn't see your comment before my edit.
Jappie
+1  A: 

I think DATEADD should do the proper thing.

Unreason
I don't see how you'd use DateAdd. Customer DOB's vary.. i.e 04/01/1965, 02/06/1982 etc etc..
Wes Price
@Wes Price, see my answer.
Denis Valeev
+3  A: 

Would something like this work for you?

select * from Customers c 
where dateadd(year, 1900-year(dob), dob) 
    between dateadd(year, 1900-year(getdate()), getdate())
    and dateadd(year, 1900-year(getdate()), getdate())+7
Denis Valeev
Of course! I see now. Thank you so much for your explantion. It seems so obvious now I understand how it works! Once you get stuck into looking at something the same way though you miss the obvious. Many thanks.
Wes Price
Oh come on, it's the power of SO! You know, brainstorming things.
Denis Valeev