Oracle通过手动透视保持dense_rank

时间:2017-05-18 14:14:09

标签: sql oracle12c

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

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

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  

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

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 

1 个答案:

答案 0 :(得分:2)

这有点复杂。问题是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;