如何为整个人群压平一张桌子?

时间:2014-07-07 15:51:35

标签: sql oracle

我正在努力替换当前使用PL / SQL游标迭代非常大的表的更新过程,使用展平数据更新多个列。

查询的结构使得展平结果只能通过限制为term和id返回单行。 term_eff列指示活动应何时开始出现在结果中,但结束日期没有当前限制。如何为test_person表中的所有行返回test_activity表的展平结果?

测试用例表:

create table test_person (id number,term varchar2(6));
create table test_activity(id number,term_eff varchar2(6),activity varchar2(10));
insert into test_person values(1,'201001');
insert into test_person values(1,'201101');
insert into test_person values(1,'201102');
insert into test_person values(2,'201001');
insert into test_person values(2,'201101');
insert into test_person values(2,'201102');
insert into test_activity values (1,'201001','Jump');
insert into test_activity values (1,'201001','Play');
insert into test_activity values (1,'201102','Run');
insert into test_activity values (2,'201001','Jump');
insert into test_activity values (2,'201101','Play');
insert into test_activity values (2,'201101','Run');
commit;

这是返回单行的当前查询。想要一个可以返回test_person表中所有行的值的版本。​​

select Max(CASE WHEN A.activity_rank = 1 THEN A.activity ELSE NULL END) AS activity1,
       Max(CASE WHEN A.activity_rank = 2 THEN A.activity ELSE NULL END) AS activity2,
       Max(CASE WHEN A.activity_rank = 3 THEN A.activity ELSE NULL END) AS activity3
  from (SELECT id, 
               term_eff,
               activity,
               row_number() OVER (PARTITION BY ID ORDER BY term_eff desc) AS activity_rank
          FROM test_activity
         WHERE id = 1
           AND term_eff <= '201001') A;

编辑:最终查询的预期结果:

ID  Term    Activity1   Activity2   Activity3
1   201001  Jump        Play    
1   201101  Jump        Play
1   201102  Jump        Play        Run
...     

1 个答案:

答案 0 :(得分:0)

基本上,只需删除where条件并添加group by即可。你已经完成了艰难的任务:

select id,
       Max(CASE WHEN A.activity_rank = 1 THEN A.activity ELSE NULL END) AS activity1,
       Max(CASE WHEN A.activity_rank = 2 THEN A.activity ELSE NULL END) AS activity2,
       Max(CASE WHEN A.activity_rank = 3 THEN A.activity ELSE NULL END) AS activity3
from (SELECT id, term_eff, activity,
             row_number() OVER (PARTITION BY ID ORDER BY term_eff desc) AS activity_rank
      FROM test_activity
      WHERE term_eff <= '201001'
     ) A
group by id;