Reputation: 79
Please go through this edited table.
You can assume order_header_key as order no.
I want to get the list of order nos whose current status is 3 and previous status was 2, and the status date(status3)-status date(2) <=3 days for that order
in the following table for order no-1 'date(status 3)' - 'date(status 2) = 20 OCT - 19 OCT which is less than 3 days--> So valid order
but for order no 3 'date(status 3)' - 'date(status 2)' = 30 OCT - 24 OCT which is more than 3 days so invalid order
order no 2 in invalid since the statuses are 3 and 1 , 2 is missing
Upvotes: 3
Views: 297
Reputation: 1269773
Use lag()
:
select o.*
from (select o.*,
lag(o.status_date) over (partition by o.order_no order by o.status_date ) as prev_sd,
lag(o.status) over (partition by o.order_no order by o.status_date) as prev_status
from orders o
) o
where prev_status = 2 and status = 3 and
(status_date - prev_sd) <= 3;
Upvotes: 3
Reputation:
Analytic functions (lag()
in this case) allow you to avoid joins and/or subqueries, and may (and often will) be much faster.
with
-- begin test data; not part of the solution
orders ( order_no, status, status_date ) as (
select 1, 1, to_date('18-OCT-16', 'DD-MON-YY')from dual union all
select 1, 2, to_date('19-OCT-16', 'DD-MON-YY')from dual union all
select 1, 3, to_date('20-OCT-16', 'DD-MON-YY')from dual union all
select 1, 1, to_date('20-OCT-16', 'DD-MON-YY')from dual union all
select 1, 3, to_date('23-OCT-16', 'DD-MON-YY')from dual union all
select 1, 2, to_date('24-OCT-16', 'DD-MON-YY')from dual union all
select 1, 1, to_date('30-OCT-16', 'DD-MON-YY')from dual
),
-- end test data; solution is the word "with" from above, plus the query below
prep ( order_no, status, status_date, prev_status, prev_status_date) as (
select order_no, status, status_date,
lag(status) over (partition by order_no order by status_date),
lag(status_date) over (partition by order_no order by status_date)
from orders
)
select order_no
from prep
where status = 3 and prev_status = 2 and prev_status_date - status_date <= 3
;
ORDER_NO
--------
1
Upvotes: 2
Reputation: 311326
Assuming an order can't have more than one entry per order_no/status combination, you could join two subqueries:
SELECT s3.order_no
FROM (SELECT *
FROM orders
WHERE status = 3) s3
JOIN (SELECT *
FROM orders
WHERE status = 2) s2 ON s3.order_no = s2.order_no AND
s3.status_date - s3.status_date <= 3
Upvotes: 3