Sql 以日期为轴以获取层次结构中节点和的汇总

Sql 以日期为轴以获取层次结构中节点和的汇总,sql,oracle,Sql,Oracle,假设我们有表EMP,其中包含父子关系: manager employee ------- ---------- NULL Johnson Johnson Ketler Ketler Braun Ketler Cooper 和表格合同,包含员工讨价还价的历史记录: date_of_contract employee amount_of_contract ---------------- ---------- ---------------

假设我们有表EMP,其中包含父子关系:

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
目标是在单个查询中获得contracts表中所有可能天数的类似结果,在给定示例中如下所示:

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
附言。 以下是创建环境管理计划和合同的代码:

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);

您可以使用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进行节点求和并不感兴趣,所以这里有一个替代方案,它使用SYS\u CONNECT\u BY\u路径,并在类似的

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

结果视图的结构正确,但其中的值不正确。@griboedov,因此pivot之前的分层查询导致了问题。为了得到正确的答案,我重做了一遍,但我并不为此疯狂。如果我能想出一个更好的方法来汇总节点上的总和,那么构造起来可能会更容易。因为在contracts表中可能有n天,所以在pivot in条件下不要被限制到天是很重要的。根据上面的代码,我可以以某种方式构造嵌入在字符串中的动态查询。但如何将列数未知的查询提取到集合中?这是一种痛苦。但是,从技术和用户体验的角度来看,如何将列数未知的查询提取到集合中是一个难题。您需要与用户交谈以确定如何显示它。所涉及的客户端工具也会影响您的解决方案。