tags:

views:

91

answers:

2

I am struggling to find a working query in SQLite, that will return my records in their upcoming birthday along with the number of days it will happen

CREATE TABLE contact_birthday ('contact_id' varchar,'data1' varchar,'display_name' varchar)

data1 holds the birthday in YYYY-MM-DD format

Something like:

"1986-06-28","Angel","0"
"1979-06-29","Bea","1"
"1984-07-02","John","4"
"1984-06-26","Mark","364"

I've found some other results but they are working for MySQL, or SQL Server not in SQLite.

How would be the query in SQLite without user defined functions?

A: 

I don't have SQLLite available to test, but this should do the trick...

SELECT JULIANDAY('NOW') - JULIANDAY(data1) FROM contact_birthday ORDER BY JULIANDAY('NOW') - JULIANDAY(data1)

You could also use the STRFTIME function, but I find the JULIANDAY function to be more readable.

Darvis Lombardo
It's not good at all. It does not ignore the year. It orders the birthdays in descending order only. Also AFAIK julianday is only for part of the day 12AM-12PM, so it will result in different results afternoon.
Pentium10
Wow! I take the time to answer your question and because it isn't EXACTLY what you want you down-vote me rather than taking the time to clarify what you are asking for? I'm sorry I wasted your time, but more sorry that I wasted mine. I'll return the favor with the down-vote since your question wasn't clear on EXACTLY what you wanted.
Darvis Lombardo
@Darvis Lombardo I don't know why people are making noise because of some down vote. It counts nothing compared to a good answer 25 points :). My question is clear enough, and I have example too. You misread my question, probably you didn't understood what `upcoming birthdays` mean.
Pentium10
@Pentium10 - It's not the down vote itself that I have a problem with. It's the hasty manner in which it was given. If you suspected I misunderstood what you needed you should have had the courtesy to offer a clarification. You tell me "my question is clear enough" but then you turn around and tell Matt "Probably I have some problems explaining what I really need". I think the latter is the case.
Darvis Lombardo
If that makes you happier I removed my own down vote.
Pentium10
+1  A: 

I got it to work using julianday (the only way to get a 'day' count AFAIK)

select name,
julianday(strftime('%Y', 'now')||strftime('-%m-%d', data1))-julianday('now') as birthday
from foo
where birthday between -1 and 30;

My result:

Angel|-0.479438499547541

Bea|0.520561488810927

John|3.52056147716939

Quick explanation:

julianday(strftime('%Y', 'now') <- this pulls the current year so that julianday for data1 doesn't consider years from the 80's

||strftime('-%m-%d', data1)) <- this concatenates the month/day for the actual birthday to the current year

where birthday between -1 and 30; <- the -1 ensures you will see results all the way up through 'today'. The 30 is the maximum amount of days you want to see in advance.

Edit 1:

Here's a modification that uses seconds since 1970 epoch rather than julian day:

select name,
(strftime('%s',strftime('%Y', 'now')||strftime('-%m-%d', data1))-strftime('%s','now'))/86400.0 as birthday
from foo
where birthday between -1 and 30
order by birthday;

Result:

Angel|-0.487118055555556

Bea|0.512881944444445

John|3.51288194444444

Edit 2: [Pentium10]

includes proper localtime

select data1,display_name,
(strftime('%s',strftime('%Y', 'now','localtime')||strftime('-%m-%d', data1))-strftime('%s','now','localtime'))/86400.0 as birthday
from contact_birthday
order by birthday asc

Edit 3: [Pentium10]

includes the order by if from today to next year this time are exactly 365 days
** still needs the dynamic calculation of 365 day, as that can be 366 for leap years

select data1,display_name,
((strftime('%s',strftime('%Y', 'now','localtime')||strftime('-%m-%d', data1))-strftime('%s','now','localtime'))/86400.0+1+365) % 365 as birthday
from contact_birthday
order by birthday asc

Edit 4: [Matt]

This actually might work for you:

select data1,name,
365-(strftime('%s',strftime('%Y', 'now', '+1 year', 'localtime')||strftime('-%m-%d', data1))-strftime('%s','now','localtime'))/86400.0 as birthday
from foo
order by birthday asc

Edit 5: [Pentium10]
THE ANSWER

select data1,display_name,
((strftime('%s',strftime('%Y', 'now','localtime')||strftime('-%m-%d', data1))-strftime('%s','now','localtime'))/86400.0+1+((strftime('%s','now', 'localtime','+1 year')-strftime('%s','now',  'localtime'))/86400.0)) % ((strftime('%s','now', 'localtime','+1 year')-strftime('%s','now',  'localtime'))/86400.0) as indays
from contact_birthday
order by indays asc

Result:

1984-07-02|John|-3.65773148148151

1979-06-29|Bea|-0.657731481481505

1986-06-28|Angel|0.342268518518495

1984-06-26|Mark|2.34226851851849

1987-02-16|Matt|132.342268518519

So birthdays that are coming up in the current year will be negative (e.g. John's is 3 days in the FUTURE), birthdays that have already passed this year will be positive.

This should allow for the correct ordering.

Matt
@Matt We are almost there. I am having problems ordering this, as when I do `order by birthday` the first records are the January's. And I need the order to start with the Upcomings (eg by today, tomorrow, next month), and last month's to show up as last.
Pentium10
@Pentium10 see my edit for a modified query. Ordering birthday ascending should be correct, if I'm reading you correctly. To see farther in the past you can adjust the -1 to something lower
Matt
@Matt Probably I have some problems explaining what I really need. By upcoming I meant to include those that happened in past too, and they should show up in the end of the list as they will happen next year. Remove the between clause, and add a record that is in january, you will see that doesn't show up in the end.
Pentium10
@Pentium10 - ah, so you want a "rolling" birthday list? I'm not sure how to do that with one query. The limit is that birthday is calculated with `2010` as the year so you can never know next year's birthday. You can add another birthday column which uses year+1 but there's no way to order it correctly that I can think of
Matt
@Matt I also spotted something else. As it turns out the time calculations are based on UTC timezone, and not based on the local time. So the query will break inside the timezone offset. Not sure how to fix this?
Pentium10
@Pentium10 - I'm still working on a solution to the original problem, but you can pass `localtime` as a modifier to any SQLite date function which fill fix that. E.g. `select datetime('now', 'localtime');`
Matt
@Pentium see edit #4 - this the only way I can think of to have "roll" ordering of the birthdays.
Matt
@Matt A very big thank you. I learnt so much from this task, including the localtime modifier. I added the final working query, that displays the `in days` as wanted and will have the `rolling` effect, thus it reads dynamically the number of days till next year (365 or 366).
Pentium10
@Pentium10 - no problem, thank you for sharing the final answer.
Matt