具有不同记录的SQL增量计算

时间:2017-03-10 09:36:43

标签: sql postgresql

我正在计算calc_table批次运行之间的金额差异,并将其存储在delta_table中。每批次运行calc_table的记录数可能会有所不同。

我可以计算差异,但我不知道如何处理新的或删除的记录,因为SQL中的JOINS会有所不同。我相信我需要使用FULL JOIN,但是我在构建SQL查询时遇到了问题。

注意:batch_id并不总是递增1.并且查询应该在calc_table中,因为这是存储金额的地方。 delta_table将包含calc_table数量之间的差异。

这是我目前的SQL :(我正在使用PostgreSQL)

select c2.batch_id, c2.c_id, c2.date, 
       (c2.amount1 - c1.amount1) as amount1, (c2.amount2 - c1.amount2) as amount2
from calc_table c1 inner join calc_table c2 on c1.c_id = c2.c_id 
where c1.batch_id = 100 and c2.batch_id = 101

* c1.batch_id and c2.batch_id are PARAMETERS.

这给了我所有预期的c_id(删除和新记录)。但我无法正确构建它以给出我对delta计算的预期结果。

SELECT coalesce(c2.c_id, c1.c_id) as c_id
FROM
  (select * from calc_table where batch_id = 100) c1
FULL OUTER JOIN
  (select * from calc_table where batch_id = 101) c2
ON c1.id = c2.id
group by coalesce(c2.c_id, c1.c_id);

这是calc_table的第一次运行:(batch_id = 100)

calc_table:
-----------------------------------------------------
id | batch_id | c_id | date       | amount1 | amount2
-----------------------------------------------------
1  | 100      | C001 | 2017-03-01 | 100     | 200 
2  | 100      | C002 | 2017-03-01 | 100     | 200 
3  | 100      | C003 | 2017-03-01 | 100     | 200 

如果用户再次运行:(batch_id = 101)

4  | 101      | C001 | 2017-03-01 | 200     | 200 
5  | 101      | C002 | 2017-03-01 | 150     | 220 
6  | 101      | C003 | 2017-03-01 | 170     | 250 
7  | 101      | C004*| 2017-03-01 | 210     | 250  

* C004 is a new record

应计算它们之间的差值(batch_id 101减去100)并存储在delta_table中:

delta_table:
------------------------------------------------------
id | batch_id | c_id | date       | amount1 | amount2 
------------------------------------------------------
1  | 101      | C001 | 2017-03-01 | 100     | 0       
2  | 101      | C002 | 2017-03-01 | 50      | 20      
3  | 101      | C003 | 2017-03-01 | 70      | 50      
4  | 101      | C004 | 2017-03-01 | 210     | 250     

如果用户再次运行:(batch_id = 104,id 8-10)

* Rows 1-7 (same as before)

calc_table:
-----------------------------------------------------
id | batch_id | c_id | date       | amount1 | amount2
-----------------------------------------------------
1  | 100      | C001 | 2017-03-01 | 100     | 200 
2  | 100      | C002 | 2017-03-01 | 100     | 200 
3  | 100      | C003 | 2017-03-01 | 100     | 200 
4  | 101      | C001 | 2017-03-01 | 200     | 200 
5  | 101      | C002 | 2017-03-01 | 150     | 220 
6  | 101      | C003 | 2017-03-01 | 170     | 250 
7  | 101      | C004 | 2017-03-01 | 210     | 250  

8  | 104      | C001 | 2017-03-01 | 200     | 200 
9  | 104      | C002 | 2017-03-01 | 400     | 200 
10 | 104      | C003 | 2017-03-01 | 400     | 220 

* Note: C004 was deleted

应计算它们之间的差值(batch_id 104减去101)并存储在delta_table中:

* Rows 1-4 (same as before), new delta = id 5-8

delta_table:
------------------------------------------------------
id | batch_id | c_id | date       | amount1 | amount2 
------------------------------------------------------
1  | 101      | C001 | 2017-03-01 | 100     | 0       
2  | 101      | C002 | 2017-03-01 | 50      | 20      
3  | 101      | C003 | 2017-03-01 | 70      | 50      
4  | 101      | C004 | 2017-03-01 | 210     | 250     

5  | 104      | C001 | 2017-03-01 | 0       | 0       
6  | 104      | C002 | 2017-03-01 | 250     | -20     
7  | 104      | C003 | 2017-03-01 | 230     | -30     
8  | 104      | C004 | 2017-03-01 | -210    | -250    

2 个答案:

答案 0 :(得分:0)

也许试试FULL JOIN

假设你计算delta的batch_id总是增量为1.这样的东西:

SELECT COALESCE(new.batch_id, old_padded_with_deleted.batch_id) AS batch_id,
       COALESCE(new.c_id, old_padded_with_deleted.c_id) AS c_id,
       COALESCE(new.date, old_padded_with_deleted.date) AS date, --new.amount1, old_padded_with_deleted.amount1,
       CASE WHEN new.amount1 IS NULL THEN -old_padded_with_deleted.amount1 ELSE (new.amount1 - coalesce(old_padded_with_deleted.amount1, 0)) END AS amount1,
       CASE WHEN new.amount2 IS NULL THEN -old_padded_with_deleted.amount2 ELSE (new.amount2 - coalesce(old_padded_with_deleted.amount2, 0)) END AS amount2
FROM calc_table new
FULL JOIN (
  SELECT coalesce(old.batch_id, deleted.batch_id)+1 AS batch_id, coalesce(old.c_id, deleted.c_id) AS c_id, coalesce(old.date, deleted.date) AS date,
         coalesce(old.amount1, deleted.amount1) AS amount1, coalesce(old.amount2, deleted.amount2) AS amount2
  FROM delta_table AS deleted
  FULL JOIN calc_table AS old ON old.batch_id = deleted.batch_id AND old.c_id = deleted.c_id
) AS old_padded_with_deleted ON old_padded_with_deleted.c_id = new.c_id
                        AND old_padded_with_deleted.batch_id = new.batch_id
WHERE
  new.batch_id = 101 OR old_padded_with_deleted.batch_id = 101

答案 1 :(得分:0)

使用此SQL解决了它:

select c1.c_id, 
sum(case when c1.batch_id = 100 then (c1.amount1 * -1) else (c1.amount1 * 1) end) as amount1
from calc_table c1
where c1.batch_id = 100 or c1.batch_id = 101
group by c1.c_id