#TABLE1
idno | amount
-------------
1 | 700
2 | 500
#table2中
idno | amount1 | amount2 | amount3 | acctno
------------------------------------------
1 | 100 | 200 | 300 | 001
1 | 100 | 200 | 300 | 002
2 | 100 | 200 | 300 | 001
我想要发生的是将表2中的金额分别分配到表1的金额1,金额2,金额3中,然后获得余额并应用于下一行。我已经尝试过使用CTE,但仍然坚持将运行余额传递给下一行。
查询:
Declare @table2 TABLE (idno varchar(max), amount1 decimal,amount2
decimal,amount3 decimal,acctno varchar(max))
INSERT INTO @table2 VALUES
('1',100,200,300,'001'),
('1',100,200,300,'002'),
('2',100,200,300,'001')
Declare @table1 TABLE (idno varchar(max), amount decimal)
INSERT INTO @table1 VALUES
('1',700),
('2',500);
WITH due AS (SELECT a.idno,a.amount,b.acctno,b.amount1,b.amount2,b.amount3
from @table1 a left join @table2 b on a.idno = b.idno),
payment AS (SELECT *,case when amount-amount1<0 then amount
else amount1 end as amount1pay
,case when amount-amount1<=0 then 0
when amount-amount1-amount2 <0 then amount-amount1
else amount2 end as amount2pay ,
case when amount-amount1-amount2<=0 then 0
when amount-amount1-amount2-amount3<0
then amount-amount1-amount2 else amount3 end as amount3pay
FROM due),
payment2 AS (SELECT SUM(amount-amount1pay-amount2pay-amount3pay)
OVER ( PARTITION BY idno ORDER BY acctno
ROWS UNBOUNDED PRECEDING ) as balance,* FROM payment)
select * from payment2
当前结果
balance | idno | amount | acctno | amount1 | amount2 | amount3 | amount1pay | amount2pay | amount3pay
---------------------------------------------------------------------------------------------------------
100 | 1 | 200 | 001 | 100 | 200 | 300 | 100 | 200 | 300
200 | 1 | 200 | 002 | 100 | 200 | 300 | 100 | 200 | 300
0 | 2 | 500 | 001 | 100 | 200 | 300 | 100 | 200 | 200
预期结果
balance | idno | amount | acctno | amount1 | amount2 | amount3 | amount1pay | amount2pay | amount3pay
---------------------------------------------------------------------------------------------------------
100 | 1 | 200 | 001 | 100 | 200 | 300 | 100 | 200 | 300
100 | 1 | 200 | 002 | 100 | 200 | 300 | 100 | 0 | 0
0 | 2 | 500 | 001 | 100 | 200 | 300 | 100 | 200 | 200
答案 0 :(得分:1)
这看起来非常混乱,因为这里有很多不同的事情。我不认为我完全理解你如何分配这笔钱的所有“规则”,但这个查询确实产生了预期的结果(实际上它略有不同,但我认为你的表中有一个错误,你显示“200 “对于前两行的金额应该是”700“)?
WITH Base AS (
SELECT
t1.idno,
t2.acctno,
t1.amount,
t2.amount1,
t2.amount2,
t2.amount3,
ROW_NUMBER() OVER (ORDER BY t1.idno, t2.acctno) AS row_id
FROM
@table1 t1
INNER JOIN @table2 t2 ON t1.idno = t2.idno),
RunningBalance AS (
SELECT
*,
CASE WHEN amount > amount1 + amount2 + amount3 THEN amount - amount1 - amount2 - amount3 ELSE 0 END AS new_balance
FROM
Base),
NewIdno AS (
SELECT
idno,
MIN(row_id) AS first_row_id
FROM
Base
GROUP BY
idno),
NewBalance AS (
SELECT
n.first_row_id AS row_id,
b.amount
FROM
NewIdno n
INNER JOIN Base b ON b.row_id = n.first_row_id),
Amount1 AS (
SELECT
b.row_id,
rb1.new_balance AS balance,
b.idno,
b.amount,
b.acctno,
b.amount1,
b.amount2,
b.amount3,
CASE WHEN ISNULL(n.amount, rb2.new_balance) >= b.amount1 THEN b.amount1 ELSE b.amount1 - ISNULL(n.amount, rb2.new_balance) END AS pay_amount1,
ISNULL(n.amount, rb2.new_balance) - b.amount1 AS carried_forward_1
FROM
Base b
INNER JOIN RunningBalance rb1 ON rb1.row_id = b.row_id
LEFT JOIN RunningBalance rb2 ON rb2.row_id = b.row_id - 1
LEFT JOIN NewBalance n ON n.row_id = b.row_id),
Amount2 AS (
SELECT
*,
CASE WHEN carried_forward_1 >= amount2 THEN amount2 ELSE carried_forward_1 END AS pay_amount2,
carried_forward_1 - CASE WHEN carried_forward_1 >= amount2 THEN amount2 ELSE carried_forward_1 END AS carried_forward_2
FROM
Amount1),
Amount3 AS (
SELECT
*,
CASE WHEN carried_forward_2 >= amount3 THEN amount3 ELSE carried_forward_2 END AS pay_amount3
FROM
Amount2)
SELECT
balance,
idno,
amount,
acctno,
amount1,
amount2,
amount3,
pay_amount1,
pay_amount2,
pay_amount3
FROM
Amount3;
我的结果是:
balance idno amount acctno amount1 amount2 amount3 pay_amount1 pay_amount2 pay_amount3
100 1 700 001 100 200 300 100 200 300
100 1 700 002 100 200 300 100 0 0
0 2 500 001 100 200 300 100 200 200
我正在使用的一些规则:
那它是如何运作的?
步骤1 - 订购数据并添加索引(row_id)
这只是两个表中的基础数据,显示了我们需要分配的数量以及我们分配的行数:
idno acctno amount amount1 amount2 amount3 row_id
1 001 700 100 200 300 1
1 002 700 100 200 300 2
2 001 500 100 200 300 3
第2步 - 计算出运行余额
如果我们分配每行可用的全部金额,这将计算剩余多少钱:
idno acctno amount amount1 amount2 amount3 row_id new_balance
1 001 700 100 200 300 1 100
1 002 700 100 200 300 2 100
2 001 500 100 200 300 3 0
第3步 - (插曲)我们需要知道我们将在第一个
分配数据的行这只是每个idno的第一个row_id:
idno first_row_id
1 1
2 3
第4步 - 稍微浪费,因为我们可以在最后一步中完成这项工作
我们只需要将总数分配到每个“第一”行:
row_id amount
1 700
3 500
第5步 - 这是我们正确处理运行平衡的地方
对于每一行,规则是我们从“新余额”开始,该新余额仅存在于每个要分配的金额的第一行。如果这不是第一行,那么我们使用运行余额,但我们从前一行(rb2.row_id = b.row_id - 1)获取此值。我们将始终拥有其中一个:
row_id balance idno amount acctno amount1 amount2 amount3 pay_amount1 carried_forward_1
1 100 1 700 001 100 200 300 100 600
2 100 1 700 002 100 200 300 100 0
3 0 2 500 001 100 200 300 100 400
因此,结转不是下一行的内容,而是要分配给下一个数量(在这种情况下为2)。
请注意,这适用于您的数据集,但如果每个idno有两行以上,则无效。如果每个idno有两行以上,那么你只需要添加另一个阶段来处理这个场景。
第6步 - 继续
对于每个金额,我们需要将其从先前计算结转的金额中扣除,给出我们可以分配给该金额的金额,以及结转到下一次计算的金额(对于金额3来说是多余的)因为没有金额4)。