如何将预算值分配给Postgresql中的实际行

时间:2014-02-09 20:49:06

标签: sql postgresql join aggregate-functions outer-join

预算表包含有负载的作业:

create temp table budget (
  job char(20) primary key,
  load numeric(4,1) not null check (load>0 )
  );
insert into budget values ( 'programmer', 3 );
insert into budget values ( 'analyst', 1.5 );

实际表包含员工的实际负载:

create temp table actual (
  job char(20),
  employee char(20),
  load numeric(4,1) not null check (load>0 ),
  contractdate date,
  primary key (job, employee)
  );

insert into actual values ( 'programmer', 'John',  1, '2014-01-01' );
-- half time programmer:
insert into actual values ( 'programmer', 'Bill', 0.5, '2014-01-02' ); 

insert into actual values ( 'analyst', 'Aldo', 1, '2014-01-03' );
insert into actual values ( 'analyst', 'Margaret', 1, '2014-01-04' ); 

结果表应显示预算和实际作业之间的差异,以便预算负载 按合同日期顺序分发给员工。

如果预算负荷大于工作负荷总和,则将空预算线与空员工分开 应该出现。

在上面的数据中,缺少1.5名程序员,0.5名分析师更多。

结果应为

Job        Employee  Budget  Actual  Difference

programmer John      1       1       0
programmer Bill      0.5     0.5     0
programmer           1.5     0       1.5
analyst    Aldo      1       1       0
analyst    Margaret  0.5     1       -0.5

如何在现代Postgresql中创建这样的表? 可以使用完全连接或其他想法对功能进行排名吗?

我试过

select
 coalesce(budget.job, actual.job ) as job,
 employee,
 budget.load as budget,
 coalesce(actual.load,0) as actual,
 coalesce(budget.load,0)-coalesce( actual.load,0) as difference
from budget full join actual using (job)
order by 1, contractdate

但这不会将预算负担分配给员工行。

我也在pgsql-general邮件列表中发布了这个。

1 个答案:

答案 0 :(得分:0)

以下查询可以获得您想要的内容:

select job, employee, budget, actual,
       (budget - cumload) as diff, contractdate
from (select coalesce(b.job, a.job ) as job, a.contractdate,
             a.employee,
             b.load as budget,
             coalesce(a.load,0) as actual,
             sum(a.load) over (partition by a.job order by a.contractdate NULLS last) as cumload
      from budget b join
           (select a.*
            from actual a
            union all
            select b.job, NULL, NULL, NULL
            from budget b
           ) a
           on b.job = a.job
     ) ab
where contractdate is not null or budget > cumload
order by job, contractdate

SQL小提琴是here

请注意,这会使用union all来引入查询所需的额外行。您希望使用full outer join执行此操作,但在满足join条件时不会生成额外的行。

此外,您正在寻找的逻辑需要一个累积总和,Postgres乐意提供。