Search code examples
mysqlwindow-functions

MySQL window function get difference between two dates where status is same on that group


What I want to do:

Find the last received row for a 'awb'. Get the current_status in that row. If the current_status is any of 'PICKUP EXCEPTION', 'OUT FOR PICKUP', 'PICKUP RESCHEDULED' then find the row with the first occurrence of these statuses for that specific 'awb' Check number of days between first occurrence and last occurrence of those STATUSES for the 'awb' and output the 'awbs' that have more than 2 days difference.

What I have done:

WITH ranked_order_status AS (
  SELECT os.*,  
  ROW_NUMBER() OVER (PARTITION BY awb ORDER BY STR_TO_DATE(recived_at,'%m/%d/%y %T') desc) AS occurance
  FROM order_status AS os 
),
filtered_last_occurance_in_list as (
 select * from ranked_order_status where occurance=1 and current_status in ('PICKUP EXCEPTION', 'OUT FOR PICKUP', 'PICKUP RESCHEDULED')
),
all_awb_with_last_status_in_list as 
(
 select * from order_status os2  where awb in (select awb from filtered_last_occurance_in_list) order by awb
)
select id, recived_at, awb,current_status from all_awb_with_last_status_in_list

Current Output:

id  |recived_at   |awb           |current_status    |
----|-------------|--------------|------------------|
2413|5/7/21 6:13  | 1091108643160|OUT FOR PICKUP    |
2414|5/7/21 6:14  | 1091108643160|OUT FOR PICKUP    |
2501|5/7/21 10:55 | 1091108643160|PICKUP EXCEPTION  |
2503|5/7/21 11:13 | 1091108643160|PICKUP EXCEPTION  |
1337|4/30/21 7:44 |14325421720410|OUT FOR PICKUP    |
1399|4/30/21 17:39|14325421720410|PICKUP EXCEPTION  |
1476|5/1/21 6:09  |14325421720410|PICKUP RESCHEDULED|
1500|5/1/21 11:09 |14325421720410|PICKUP EXCEPTION  |
  77|4/22/21 7:18 |19041127718646|OUT FOR PICKUP    |
 121|4/22/21 11:17|19041127718646|PICKUP EXCEPTION  |
  81|4/22/21 7:18 |19041128001310|OUT FOR PICKUP    |
 124|4/22/21 11:18|19041128001310|PICKUP EXCEPTION  |
  83|4/22/21 7:18 |19041128018585|OUT FOR PICKUP    |
 125|4/22/21 11:18|19041128018585|PICKUP EXCEPTION  |
 979|4/27/21 12:19|19041129734005|PICKUP EXCEPTION  |
1334|4/30/21 6:48 |19041130453211|OUT FOR PICKUP    |
1372|4/30/21 11:19|19041130453211|PICKUP EXCEPTION  |
1534|5/1/21 18:47 |19041130453211|PICKUP EXCEPTION  |
1483|5/1/21 7:18  |19041130642631|OUT FOR PICKUP    |
1490|5/1/21 8:18  |19041130642631|PICKUP EXCEPTION  |
1688|5/3/21 10:47 |19041130642631|PICKUP EXCEPTION  |

Expected Result: Let say for awb = 1091108643160, I need to create a new column with the name delay using (5/7/21 11:13 - 5/7/21 10:55) = 18m

 id   recived_at      awb           current_status 
2413|5/7/21 6:13  | 1091108643160|OUT FOR PICKUP    |
2414|5/7/21 6:14  | 1091108643160|OUT FOR PICKUP    |
2501|5/7/21 10:55 | 1091108643160|PICKUP EXCEPTION  | -> this is first occurrence of same status
2503|5/7/21 11:13 | 1091108643160|PICKUP EXCEPTION  | -> this is last row

Solution

  • calculate date difference between last row of a awb and first occurrence of that (status and awb)

    WITH cte AS ( SELECT DISTINCT
                         awb, 
                         FIRST_VALUE(current_status) OVER (PARTITION BY awb ORDER BY date DESC) current_status
                  FROM source )
    SELECT awb, DATEDIFF(MAX(date), MIN(date))
    FROM source
    JOIN cte USING (awb, current_status)
    GROUP BY awb