1

I'm attempting to write a query that finds the user's work anniversary for the current month and considers a leap year as well (don't get an idea how to manage within the query)

Table "emp_detail":

emp_no join_date
1 2002-06-10
2 2022-06-25
3 2020-02-29
4 2002-02-15
5 2011-02-01

So far I have tried the below query:

SELECT no,
       join_date
       CASE WHEN DATEADD(YY,DATEDIFF(yy,join_date,GETDATE()),join_date) < GETDATE() 
            THEN DATEDIFF(yy,join_date,GETDATE())
            ELSE DATEDIFF(yy,join_date,GETDATE()) - 1 
       END AS 'anniversary'
FROM emp_detail
WHERE 'status' = 'active' 
HAVING MONTH(join_date) = 06/07/08 -- ...so on

EDIT: Expected output:

For FEBRUARY month current year 2022

emp_no join_date anniversary_date
3 2020-02-29 2022-02-28 (Here, want get 29 Feb 2020 leap year record with non leap year 2022)
4 2002-02-15 2022-02-15
5 2011-02-01 2022-02-01

Looking for a way to display employees with anniversary dates coming up at the start of the current month considering the leap year.

Am I going in the right direction? Any help would be great.

Martin
  • 22,212
  • 11
  • 70
  • 132
Emma
  • 95
  • 1
  • 10
  • 1
    Can you share a full sample input table and the expected output? – lemon Jun 30 '22 at 17:44
  • 1
    you say considering the leap year, but don't explain what you want. what is the work anniversary in 2022 for someone with a join date of 2020-02-29? – ysth Jun 30 '22 at 17:53
  • "coming up in the start of current month" doesn't make sense. do you mean in the current month? in the following month? – ysth Jun 30 '22 at 17:55
  • 1
    @ysth Thank you for your reply. YES, you are right, I mean to say a "current month" which is passing in the `having` clause, as from "today" I'm expecting the result of the `"JULY"` month record, and by `leap year` >> if emp. work anniversary in 2022 for someone with a join date of 2020-02-29 what should I do? can we consider the `1st MAR or 28th FEB`? I also need that emp. record – Emma Jul 01 '22 at 04:45
  • yes, it could be considered (in non-leap current years) Mar 1 or Feb 28 or both or neither. what do you want? – ysth Jul 01 '22 at 05:04
  • @ysth I would like to consider FEB 28 – Emma Jul 01 '22 at 05:40
  • Is there a hidden rationale behind output anniversary years? How do you decide to use 2022 in place of 2020, or even maybe in place of years like 2019 and 2021? Or is it just a typo and all years should be 2022? @Emma – lemon Jul 01 '22 at 10:22
  • @lemon yes correct there was a typo, anniversary year should be the current year – Emma Jul 01 '22 at 10:32
  • Your tag says `[mysql]` but that DATEADD syntax looks like SQL Server to my eye. What is the database engine? – pilcrow Jul 01 '22 at 13:39
  • @pilcrow Thanks for inform, actually I was still attempting to write queries with the help of some old threads and RnD, `DB engine: MariaDB >> InnoDB `, I'm still college student, So might be possible, I'm making a mistake, looking forward to all guidance – Emma Jul 01 '22 at 13:56

3 Answers3

1

You can split your problem into two steps:

  • filtering your "join_date" values using the current month
  • changing the year to your "join_date"
  • getting the minimum value between your updated "join_date" and the last day for that date (>> this will handle leap years kinda efficiently wrt other solutions that attempt to check for specific years every time)
WITH cte AS (
    SELECT emp_no,
           join_date,
           STR_TO_DATE(CONCAT_WS('-',
                                 YEAR (CURRENT_DATE()),
                                 MONTH(join_date     ),
                                 DAY  (join_date     )),
                       '%Y-%m-%d') AS join_date_now
    FROM tab 
    WHERE MONTH(join_date) = MONTH(CURRENT_DATE())
      AND YEAR(join_date)  < YEAR(CURRENT_DATE())
)
SELECT emp_no,
       join_date,
       LEAST(join_date_now, LAST_DAY(join_date_now)) AS anniversary_date
FROM cte

Check the demo here

Note: in the demo, since you want to look at February months and we are in July, the WHERE clause will contain an additional -5 while checking the month.

lemon
  • 14,875
  • 6
  • 18
  • 38
  • Thanks, @lemon for your guidance, I'll check it to inform if any – Emma Jul 01 '22 at 13:59
  • Thanks for your efforts, but it also didn't get the accurate result | Let's say if emp. join on `01-07-2022`, then this emp. the record still covers the result on an anniversary list, could you pls see it on your demo, I have tested it, Thanks! – Emma Jul 01 '22 at 15:16
  • I'm assuming that you are using the standard `DATE` type for your "*emp_join*" field. Is this assumption correct? Also can you share an updated link of the demo? @Emma – lemon Jul 01 '22 at 15:16
  • Hello lemon, pls see the [example](https://www.db-fiddle.com/f/nGBqnCtbtDn6YUKsGHLxzF/1) **Note:** currently I'm not considering the FEB month data but JULY month data – Emma Jul 01 '22 at 15:36
  • Oh yes, I get your point: we need to exclude those that have entered the company this year. I've added a condition on the year inside the query. Check the updated demo. – lemon Jul 01 '22 at 15:39
1

Most (all?) SQL engines already handle year arithmetic involving leap days the way you want: folding the leap day to the final day of February.

So, computing the employee's join_date + INTERVAL x YEAR will handle '2020-02-29' correctly. To compute that interval in MySQL/MariaDB for the current year, you may use TIMESTAMPDIFF compute the difference between EXTRACTed years yourself:

SELECT emp_no,
       join_date,
       join_date +
         INTERVAL (EXTRACT(YEAR FROM CURDATE()) -
                   EXTRACT(YEAR FROM join_date)) YEAR
         AS "anniversary_date_this_year",
       ....
pilcrow
  • 56,591
  • 13
  • 94
  • 135
  • 1
    I have tried your query, but I'm not getting why only for **emp no. 3** only having `2022` year with `anniversary_date_this_year` `2022-07-01` and having emp join date `2020-07-01` other having `2021` year, pls see [example](https://www.db-fiddle.com/f/pVdA39PcbTbmrHYrfTfKCj/1) – Emma Jul 01 '22 at 16:02
  • @Emma, my mistake there. Corrected. – pilcrow Jul 02 '22 at 12:15
  • 1
    is it possible to get through the query and display `year+ month` `TIMESTAMPDIFF(YEAR, join_date, CURDATE()) AS difference` as difference Like *2 Years 11 months, 1 Year 1 month* @pilcrow – Emma Jul 12 '22 at 09:41
  • @Emma, I’d search this site for an answer to that and, if not found, ask. – pilcrow Jul 12 '22 at 11:50
  • 1
    I have searched for this and use something like this `TIMESTAMPDIFF( MONTH, join_date, CURDATE() ) % 12 as month` Pls review and let me know if this is valid [Example](https://www.db-fiddle.com/f/pVdA39PcbTbmrHYrfTfKCj/4) – Emma Jul 13 '22 at 06:57
  • But I think Need your help with the "Year" or "Years" alias, `2 **Years** 11 **months**, 1 **Year** 1 **month**` – Emma Jul 13 '22 at 07:01
  • @Emma, I think you should pose this part of your problem as a [separate question](https://stackoverflow.com/questions/ask). – pilcrow Jul 13 '22 at 10:12
  • ohh, thanks let me create a new question – Emma Jul 13 '22 at 10:36
0

You can make use of extract function in MySQL

select * from emp_detail where extract( month from (select now())) = extract( month from join_date)  and extract( year from (select now())) != extract( year from join_date);

The above query will display all employees whose work anniversary is in the current month.
For the below table:
enter image description here
The above query will display the following rows.
enter image description here

The following query also considers leap year.

  1. If the employee has joined on Feb-29 in a leap year and the current year is a non-leap year, then the query displays Anniversary Date as 'currentYear-Feb-28'

  2. If the employee has joined on Feb-29 in a leap year and the current year is also a leap year, then the query displays Anniversay Date as 'currentYear-Feb-29'

    select empId , 
    case 
        when ( ( extract(year from (select now()))%4 = 0 and extract(year from (select now()))%100 != 0 ) or extract(year from (select now())) % 400 = 0 ) then 
            cast( concat( extract(year from (select now())), '-', extract( month from join_date),'-',  extract( day from join_date) ) as date) 
        when ( ( (extract(year from join_date) % 4 = 0 and extract(year from join_date)%100 != 0) or extract( year from join_date)%400 = 0) and extract(month from join_date) =2 
        and extract(day from join_date) = 29 ) then 
                cast( concat( cast( extract(year from (select now())) as nchar), '-02-28') as date)
        else cast( concat( extract(year from (select now())), '-', extract( month from join_date),'-',  extract( day from join_date) ) as date) 
    end as AnniversaryDate
    from emp_detail
    where extract(year from join_date) != extract(year from (select now()));
    

Emp_detail data enter image description here

For this data the query will show the following rows enter image description here

Further if you want to filter the date to current month only, you can make use of extract function.

vishal rana
  • 33
  • 1
  • 1
  • 7
  • Thanks for the replay, I think with your query I'm able to find the current month record, but as have to consider the year which is a leap year, so could you pls help me with that (FYI: see the above comments for better explanation.) Thank you! – Emma Jul 01 '22 at 06:02
  • Modified answer – vishal rana Jul 01 '22 at 09:23