透视日期以获得层次结构中节点总和的累计

时间:2015-04-01 18:08:08

标签: sql oracle

想象一下,我们有表emps,包含父子关系:

manager   employee
------- ----------
NULL       Johnson
Johnson    Ketler
Ketler     Braun
Ketler     Cooper

和表合同,包含员工讨价还价的历史:

date_of_contract    employee    amount_of_contract
----------------    ----------  ------------------
25.03.2015          Ketler                      4
25.03.2015          Braun                       3
25.03.2015          Cooper                      2
25.03.2015          Johnson                     9
26.03.2015          Ketler                      1
26.03.2015          Braun                       4
26.03.2015          Cooper                      3
26.03.2015          Johnson                     6
27.03.2015          Ketler                      6
27.03.2015          Braun                       2
27.03.2015          Cooper                      5
27.03.2015          Johnson                     7

我们进行查询以查看2015年3月25日的等级合约总和:

with t0 as (
    select e.manager, e.employee, c.date_of_contract, c.amount_of_contract
      from emps e inner join
      contracts c on c.employee=e.employee where date_of_contract = to_date('25.03.15')
  ), t1 as (
    select t.*, (
      select sum(amount_of_contract) from t0 p
          connect by prior employee = manager
          start with p.employee = t.employee
      ) tot, level lvl
      from t0 t
      connect by prior t.employee = t.manager
      start with t.manager is null
  )
select
  lpad(' ',2*(lvl-1)) || employee employee,
  tot tot_25_03_15  
    from t1 t

此查询产生以下结果:

EMPLOYEE    TOT_25_03_15
---------   ------------
Johnson     18
  Ketler    9
    Braun   3
    Cooper  2

目标是在单个查询中获得合同表中所有可能日期的类似结果,在给定示例中将遵循以下结果:

EMPLOYEE        TOT_25_03_15    TOT_26_03_15    TOT_27_03_15
--------------  -------------   -------------   -------------
Johnson         18              14              20
  Ketler        9               8               13
    Braun       3               4               2
    Cooper      2               3               5

P.S。 以下是创建emps和合同的代码:

create table emps (manager varchar2(50), employee varchar2(50));
insert into emps (manager, employee) values (NULL,'Johnson');
insert into emps (manager, employee) values ('Johnson','Ketler');
insert into emps (manager, employee) values ('Ketler','Braun');
insert into emps (manager, employee) values ('Ketler','Cooper');

create table contracts (date_of_contract date, employee varchar2(50), amount_of_contract number(12,0));
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('25.03.2015'),'Ketler',4);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('25.03.2015'),'Braun',3);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('25.03.2015'),'Cooper',2);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('25.03.2015'),'Johnson',9);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('26.03.2015'),'Ketler',1);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('26.03.2015'),'Braun',4);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('26.03.2015'),'Cooper',3);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('26.03.2015'),'Johnson',6);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('27.03.2015'),'Ketler',6);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('27.03.2015'),'Braun',2);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('27.03.2015'),'Cooper',5);
insert into contracts (date_of_contract, employee, amount_of_contract) values (to_date('27.03.2015'),'Johnson',7);

1 个答案:

答案 0 :(得分:2)

您可以使用Pivot首先旋转值,然后对各个日期执行求和

WITH pivoted AS 
( 
       SELECT employee, 
              "'25-MAR-15'" s25_03_15, 
              "'26-MAR-15'" s26_03_15, 
              "'27-MAR-15'" s27_03_15 
       FROM   contracts PIVOT ( Sum( amount_of_contract) FOR date_of_contract IN ('25-MAR-15', 
                                                                                  '26-MAR-15', 
                                                                                  '27-MAR-15')) ) , t0 AS 
( 
           SELECT     e.manager, 
                      e.employee, 
                      c.s25_03_15, 
                      c.s26_03_15, 
                      c.s27_03_15 
           FROM       pivoted c 
           INNER JOIN emps e 
           ON         c.employee=e.employee ) , t1 AS 
( 
       SELECT t.*, 
              ( 
                     SELECT sum(s25_03_15) 
                     FROM   t0 p connect BY prior employee = manager start WITH p.employee = t.employee ) tot_25_03_15,
              ( 
                     SELECT sum(s26_03_15) 
                     FROM   t0 p connect BY prior employee = manager start WITH p.employee = t.employee ) tot_26_03_15,
              ( 
                     SELECT sum(s27_03_15) 
                     FROM   t0 p connect BY prior employee = manager start WITH p.employee = t.employee ) tot_27_03_15,
              level                                                                                       lvl
       FROM   t0 t connect BY prior t.employee = t.manager start WITH t.manager IS NULL) 
SELECT lpad(' ',2*(lvl-1)) 
              || employee employee, 
       tot_25_03_15 , 
       tot_26_03_15 , 
       tot_27_03_15 
FROM   t1 t

SQL Fiddle

对于对节点进行求和的内联SQL,我并不感到兴奋所以这里是一个使用SYS_CONNECT_BY_PATH和LIKE上的自联接的替代方法

WITH pivoted AS 
( 
       SELECT employee, 
              "'25-MAR-15'" s25_03_15, 
              "'26-MAR-15'" s26_03_15, 
              "'27-MAR-15'" s27_03_15 
       FROM   contracts PIVOT ( Sum( amount_of_contract) FOR date_of_contract IN ('25-MAR-15', 
                                                                                  '26-MAR-15', 
                                                                                  '27-MAR-15')) ) , t0 AS 
( 
           SELECT     e.manager, 
                      e.employee, 
                      c.s25_03_15, 
                      c.s26_03_15, 
                      c.s27_03_15 
           FROM       pivoted c 
           INNER JOIN emps e 
           ON         c.employee=e.employee ) , t1 AS 
( 
       SELECT t.*, 
              sys_connect_by_path(employee, '/') path, 
              level                              lvl 
       FROM   t0 t connect BY prior t.employee = t.manager start WITH t.manager IS NULL) 
SELECT     lpad(' ',2*(b.lvl-1)) 
                      || b.employee employee, 
           sum(a.s25_03_15)         tot_25_03_15, 
           sum(a.s26_03_15)         tot_26_03_15, 
           sum(a.s27_03_15)         tot_26_03_15 
FROM       t1 a 
INNER JOIN t1 b 
ON         a.path LIKE b.path 
                      || '%' 
GROUP BY   lpad(' ',2*(b.lvl-1)) 
                      || b.employee

SQL Fiddle