Ordering of Dates and retrieving results based on current date (Birth Day List) SQLite

后端 未结 2 418
情话喂你
情话喂你 2021-01-07 15:40

I have a date stored as string in a Sqlite column, the format is YYYY-MM-DD ( Not separated into three columns for year date and month) Now I have a requirement to make a qu

相关标签:
2条回答
  • 2021-01-07 16:03

    Following will do:

    SELECT *
    FROM _table
    ORDER BY SUBSTR(DATE('NOW'), 6)>SUBSTR(birthdate, 6), SUBSTR(birthdate, 6)
    

    Check it in SQL Fiddle.

    SUBSTR(date, 6) will remove year part from date. Birthdates must be sorted in MM-DD, but first should be shown those which will happen after today, and then those which happen before today.

    SUBSTR(DATE('NOW'), 6)>SUBSTR(birthdate, 6) will return 0 for birthdates MM-DD greater or equal to today MM-DD, 1 otherwise. So, first expression will ORDER past dates after comming date. Second parameter just ORDER dates by MM-DD.

    See step by step in SQL Fiddle.

    0 讨论(0)
  • 2021-01-07 16:14

    There are quite a few ways to do it, some more efficient than others. I will suggest a solution that can be effective without changing your database format, but note that it can all get much faster (especially if we are talking about a big birthday list) if you can use separate Year,Month,Day integer columns, or a unix timestamp column.

    select *, 
    strftime('%j', 
        strftime('%Y', 'now') || '-' || 
        strftime('%m', birthday) || '-' || 
        strftime('%d', birthday)
    )
    - strftime('%j', 
        strftime('%Y', 'now') || '-' || 
        strftime('%m', 'now') || '-' || 
        strftime('%d', 'now')
    )
    as daydiff
    from users
    where daydiff >=0
    
    union all
    
    select *, 
    strftime('%j', 
        strftime('%Y', 'now') || '-' || 
        strftime('%m', birthday) || '-' || 
        strftime('%d', birthday)
    )
    - strftime('%j', 
        strftime('%Y', 'now','+1 year') || '-' || 
        strftime('%m', 'now') || '-' || 
        strftime('%d', 'now')
    ) + 366
    as daydiff
    from users
    where daydiff <366
    order by daydiff
    

    The above uses today's year and each users month and day parts to calculate day of year (e.g. today Dec 11, 2013 is day 345) and subtracts the day of year of today's date. Birthdays that occur in the current year will have a daydiff value >= 0, so we use them first. This was the first part of the union.

    The second part makes the same calculation but for those whose birthday is next year, so we add 366 to the daydiff value and make sure we only get the fields that we didn't get from the first part.

    The same query can be rewritten with a CASE WHEN instead of union. The CASE alternative will be faster because it will only fetch the rows from the users table just once, instead of twice, but it would be really ugly for me to write in this forum. On second thought, I'll write it anyway, since it is faster

    select *, 
    CASE WHEN 
      strftime('%j', 
        strftime('%Y', 'now') || '-' || strftime('%m', birthday) || '-' || strftime('%d', birthday)
      )
      - strftime('%j', 
        strftime('%Y', 'now') || '-' || strftime('%m', 'now') || '-' || strftime('%d', 'now')
      ) >= 0
    THEN 
      strftime('%j', 
        strftime('%Y', 'now') || '-' || strftime('%m', birthday) || '-' || strftime('%d', birthday)
      )
      - strftime('%j', 
        strftime('%Y', 'now') || '-' || strftime('%m', 'now') || '-' || strftime('%d', 'now')
      ) 
    ELSE 
      strftime('%j', 
        strftime('%Y', 'now') || '-' || strftime('%m', birthday) || '-' || strftime('%d', birthday)
      )
      - strftime('%j', 
        strftime('%Y', 'now') || '-' || strftime('%m', 'now') || '-' || strftime('%d', 'now')
      ) + 366 
    END
    as daydiff
    from users
    order by daydiff
    

    Also a last note. I manually add 366 on next years birthdays, but the correct thing would be to add the days of year depending on the year (365 or 366). Since we only need it for ordering, this will not cause trouble because the worst case is that it will add one to daydiff for all next year's users. So birthday on '2013-12-31' will give daydiff=20, but birthday on '2014-01-01' will give daydiff=22.

    EDIT:

    Here's a fiddle

    0 讨论(0)
提交回复
热议问题