Продолжая @ Гордона Табибитозан , когда у вас есть группировки, вы можете получить как заказ в каждой группе, так и истекшее количество дней для каждого члена группы:
-- CTE for sample data
with orders (order_no, order_stat, stat_date) as (
select 2, 'Planned', date '2000-01-01' from dual
union all select 2, 'Picked', date '2000-01-15' from dual
union all select 2, 'Planned', date '2000-01-17' from dual
union all select 2, 'Planned', date '2000-02-05' from dual
union all select 2, 'Planned', date '2000-03-31' from dual
union all select 2, 'Picked ', date '2000-04-05' from dual
union all select 2, 'Shipped', date '2000-04-10' from dual
)
-- actual query
select order_no, order_stat, stat_date, grp,
dense_rank() over (partition by order_no, order_stat, grp order by stat_date) as rnk,
stat_date - min(stat_date) keep (dense_rank first order by stat_date)
over (partition by order_no, order_stat, grp) as stat_days
from (
select order_no, order_stat, stat_date,
row_number() over (partition by order_no order by stat_date)
- row_number() over (partition by order_no, order_stat order by stat_date) as grp
from orders
)
order by order_no, stat_date;
ORDER_NO ORDER_S STAT_DATE GRP RNK STAT_DAYS
---------- ------- ---------- ---------- ---------- ----------
2 Planned 2000-01-01 0 1 0
2 Picked 2000-01-15 1 1 0
2 Planned 2000-01-17 1 1 0
2 Planned 2000-02-05 1 2 19
2 Planned 2000-03-31 1 3 74
2 Picked 2000-04-05 5 1 0
2 Shipped 2000-04-10 6 1 0
Встроенное представление по сути то, что сделал Гордон, за исключением того, что тривиально выполняет вычитание на этом уровне. Внешний запрос затем получает ранг таким же образом, но также использует аналитическую функцию, чтобы получить самую раннюю дату для этой группы, и вычитает ее из даты текущей строки. Вам, конечно, не нужно включать grp
или rnk
в ваш конечный результат, они показывают, чтобы дать более полное представление о том, что происходит.
Не совсем точно, что вы хотите, но вы можете расширить еще, например:
with cte1 (order_no, order_stat, stat_date, grp) as (
select order_no, order_stat, stat_date,
row_number() over (partition by order_no order by stat_date)
- row_number() over (partition by order_no, order_stat order by stat_date)
from orders
),
cte2 (order_no, order_stat, stat_date, grp, grp_date, rnk) as (
select order_no, order_stat, stat_date, grp,
min(stat_date) keep (dense_rank first order by stat_date)
over (partition by order_no, order_stat, grp),
dense_rank() over (partition by order_no, order_stat, grp order by stat_date)
from cte1
)
select order_no, order_stat, stat_date, grp, grp_date, rnk,
stat_date - grp_date as stat_days_so_far,
case
when order_stat != 'Shipped' then
coalesce(first_value(stat_date)
over (partition by order_no order by grp_date
range between 1 following and unbounded following), trunc(sysdate))
- min(stat_date) keep (dense_rank first order by stat_date)
over (partition by order_no, order_stat, grp)
end as stat_days_total,
stat_date - min(stat_date) over (partition by order_no) as order_days_so_far,
case
when max(order_stat) keep (dense_rank last order by stat_date)
over (partition by order_no) = 'Shipped' then
max(stat_date) over (partition by order_no)
else
trunc(sysdate)
end
- min(stat_date) over (partition by order_no) as order_days_total
from cte2
order by order_no, stat_date;
который для данных вашего образца дает:
ORDER_NO ORDER_S STAT_DATE GRP GRP_DATE RNK STAT_DAYS_SO_FAR STAT_DAYS_TOTAL ORDER_DAYS_SO_FAR ORDER_DAYS_TOTAL
---------- ------- ---------- ---------- ---------- ---------- ---------------- --------------- ----------------- ----------------
2 Planned 2000-01-01 0 2000-01-01 1 0 14 0 100
2 Picked 2000-01-15 1 2000-01-15 1 0 2 14 100
2 Planned 2000-01-17 1 2000-01-17 1 0 79 16 100
2 Planned 2000-02-05 1 2000-01-17 2 19 79 35 100
2 Planned 2000-03-31 1 2000-01-17 3 74 79 90 100
2 Picked 2000-04-05 5 2000-04-05 1 0 5 95 100
2 Shipped 2000-04-10 6 2000-04-10 1 0 100 100
Я включил некоторую логику, чтобы предположить, что «Отправлено» является окончательным статусом, и если это не было достигнуто, то последний статус все еще работает - так что посчитайте до сегодняшнего дня. Это может быть неправильно, и у вас могут быть другие значения конечного состояния (например, отменены). Во всяком случае, несколько вещей для вас, чтобы исследовать и играть с ...
Возможно, вы сможете сделать нечто подобное с match_recognize
, но я оставлю это кому-то еще.