Sql 以日期为轴以获取层次结构中节点和的汇总
假设我们有表EMP,其中包含父子关系:Sql 以日期为轴以获取层次结构中节点和的汇总,sql,oracle,Sql,Oracle,假设我们有表EMP,其中包含父子关系: manager employee ------- ---------- NULL Johnson Johnson Ketler Ketler Braun Ketler Cooper 和表格合同,包含员工讨价还价的历史记录: date_of_contract employee amount_of_contract ---------------- ---------- ---------------
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条件下不要被限制到天是很重要的。根据上面的代码,我可以以某种方式构造嵌入在字符串中的动态查询。但如何将列数未知的查询提取到集合中?这是一种痛苦。但是,从技术和用户体验的角度来看,如何将列数未知的查询提取到集合中是一个难题。您需要与用户交谈以确定如何显示它。所涉及的客户端工具也会影响您的解决方案。