sqlpostgresqldatediff

Query upcoming birthday date


My table looks like

ID | PersonName | Birthday   | IntDate
--------------------------------------
 1 | Joe        | 1977-08-20 |     820
 2 | Sandy      | 1985-02-27 |     227
 3 | Jane       | 1981-11-01 |    1101

The INDEXed helper column IntDate is just an int = month*100+days, written at insert/update and used to speed up queries for all birthdays in a given date range (e.g. between [1001;1031] for October) independent of the year. (So I don't have to filter based on EXTRACT or DATE_PART functions for day and month in the WHERE clause, as the birthday DATE includes a year in the past.)

Given a certain date (e.g. 2025-05-01), I want to query the next birthday date of the persons and the upcoming anniversary (what birthday is coming). Then I want to sort the list by the next birthday date (this or next year).

For 2025-05-01, the list might look like:

ID | PersonName | Birthday   | NextBirthday ^ | Anniversary (at upcoming birthday)
-----------------------------------------------------------
 1 | Joe        | 1977-08-20 |   2025-08-20   |          48
 3 | Jane       | 1981-11-01 |   2025-11-01   |          44
 2 | Sandy      | 1985-02-27 |   2026-02-27   |          41

Is that possible using an SQL SELECT query in PostgreSQL?


Solution

  • You use helper column (IntDate) for search and index.
    You can use this value to detect next anniversary year. Calculate those value for given date '2025-05-01' -> '501' and compare with IntDate. If greater then next birth day is in next year.

    See example. (cross joins only for simplicity of calculation)

    select *
      ,birthday+ (cAge+case when idt>intdate then +1 else 0 end)* interval '1 year' nextBirthDay
      ,cAge+case when idt>intdate then +1 else 0 end Anniversary
    from test
    cross join ( values('2025-05-01'::date)) t(cDt)  -- parameter 
    cross join lateral ( values(extract(month from cdt)*100+extract(day from cdt)
                ,(extract (year from cdt)-extract(year from birthday))::int
           ) ) c(iDt,cAge)  -- precalculations
    
    
    id personname birthday intdate cdt idt cage nextbirthday anniversary
    1 Joe 1977-08-20 820 2025-05-01 501 48 2025-08-20 00:00:00 48
    2 Sandy 1985-02-27 227 2025-05-01 501 40 2026-02-27 00:00:00 41
    3 Jane 1981-11-01 1101 2025-05-01 501 44 2025-11-01 00:00:00 44
    4 Mike 2000-05-01 501 2025-05-01 501 25 2025-05-01 00:00:00 25

    fiddle