Oracle 通过手动旋转保持 dense_rank

Oracle keep dense_rank with manual pivoting

我有一个 table 记录每个 ID 的事件日期。每个事件都有一个类型,每个事件类型和 ID 可能有零个或多个注册日期。

我需要生成一个结果集,其中包含每个不同的 ID,以及第一个开始日期、最后一个修复日期和最后一个结束日期。这很简单。但我还需要 select 每条记录的参考代码。这部分我似乎无法在同一个查询中处理。

with example_data as(
   select 'A' as id, 'START'  as t, date '2017-01-01' as d, '18' as ref from dual union all
   select 'A' as id, 'WHATEV' as t, date '2017-01-02' as d, '12' as ref from dual union all
   select 'A' as id, 'CRASH'  as t, date '2017-01-05' as d, '17' as ref from dual union all
   select 'A' as id, 'REPAIR' as t, date '2017-01-06' as d, '01' as ref from dual union all
   select 'A' as id, 'CRASH'  as t, date '2017-01-10' as d, '20' as ref from dual union all
   select 'A' as id, 'REPAIR' as t, date '2017-01-11' as d, '07' as ref from dual union all
   select 'A' as id, 'END'    as t, date '2017-01-12' as d, '14' as ref from dual union all
   select 'B' as id, 'START'  as t, date '2017-01-01' as d, '24' as ref from dual union all
   select 'B' as id, 'END'    as t, date '2017-01-10' as d, '28' as ref from dual
-- Primary key(id, t, d)   
)
select id
      ,min(case when t = 'START'  then d end) as start_date 
      ,max(case when t = 'END'    then d end) as end_date
      ,max(case when t = 'REPAIR' then d end) as repair_date
  from example_data
 where t in('START', 'END', 'REPAIR')
 group 
    by id;


ID  START_DATE  END_DATE  REPAIR_DATE
-- ----------  ---------- -----------
A   2017-01-01  2017-01-12 2017-01-11
B   2017-01-01  2017-01-10  

这是我尝试包含相应记录中的参考代码的尝试,但由于某种原因 repair_ref 为空。

select id
      ,min(case when t = 'START'  then ref end) keep (dense_rank first order by d asc)  as start_ref 
      ,min(case when t = 'END'    then ref end) keep (dense_rank first order by d desc) as end_ref
      ,min(case when t = 'REPAIR' then ref end) keep (dense_rank first order by d desc) as repair_ref
  from example_data
 where t in('START', 'END', 'REPAIR')
 group 
    by id;

这是我尝试的结果。我期待 id=A 的 repair_ref = '07'。我做错了什么?

ID START_REF END_REF REPAIR_REF
-- --------- ------- ----------
A  18        14 
B  24        28 

这有点复杂。问题是 keep 正在查看所有记录。所以,我认为你可以这样做:

select id,
       min(case when t = 'START'  then d end) keep (dense_rank first 
             order by (case when t = 'START'  then d end) asc)             as start_date,
       max(case when t = 'END'    then d end) keep (dense_rank first 
             order by (case when t = 'END'    then d end) desc nulls last) as end_date,
       max(case when t = 'REPAIR' then d end) keep (dense_rank first 
             order by (case when t = 'REPAIR' then d end) desc nulls last) as repair_date
from example_data
 where t in ('START', 'END', 'REPAIR')
 group by id;