我有一个复杂的问题要解决而不使用循环.循环似乎非常简单.但是当试图在基于Set的操作中思考时,它被证明是非常棘手的.
细节
以下是PaymentPlan表,我存储了每个客户的付款计划.
例如:客户需要支付多少费用以及支付日期.
PlanId |PaymentAmount |CustomerId |StartDate
100 |200.00 |100 |2017-01-01
200 |100.00 |100 |2017-02-01
300 |100.00 |100 |2017-03-01
400 |200.00 |100 |2017-04-01
如上表所示,它包含customerId 100的所有付款计划.
接下来我有一个名为Transaction的表.此表存储了上述付款计划的交易.
TransId |CustomerId |Amount |TransactionDate |IsReversed
100 |100 |100.00 |2017-01-01 |0
200 |100 |100.00 |2017-01-02 |0
300 |100 |60.00 |2017-01-04 |0
400 |100 |40.00 |2017-02-02 |0
500 |100 |300.00 |2017-04-02 |0
600 |100 |200.00 |2017-04-10 |1
问题是PaymentPlan和Transaction Table之间没有关系,我们无法创建一个太复杂的系统,而且系统是单片的.
我正在尝试创建一个名为TransPaymentPlanMapping的新表
将以下列格式存储两个表之间的映射.
使用循环创建映射并不难,但性能不会很好.我无法提出基于集合的解决方案.
CustomerId |transId |PlanId |RunningPaidAmount |transDateTime |IsReversed
100 |100 |100 |100 |2017-01-01 |0
100 |200 |100 |200 |2017-01-02 |0
100 |300 |200 |60 |2017-01-04 |0
100 |400 |200 |100 |2017-02-02 |0
100 |500 |300 |100 |2017-04-02 |0
100 |500 |400 |200 |2017-04-02 |0
100 |600 |400 |-200 |2017-04-10 |1
以下是映射如何完成的细分.
>在2017-01-01,客户支付100美元,结果是TransId:100
并且这个transId被分配了planId 100.为什么?因为这是
最早的计划.
>在2017-01-02客户再次支付100美元生成TransId
200再次分配给planId 100.为什么?因为它是
在第1步中部分支付.lightId 100的总金额为200美元.
> 2017-01-04客户支付60美元并生成transId:300,分配给planId:200,因为此付款计划是下一个.
>在2017-02-02上,客户为planId支付40美元的金额:200支付此支付的费用:生成400并映射到planId:200.
>客户在计划时支付的时间较晚:300和400在2017-04-02他/她决定支付300美元,其中包括planId:300和400.此付款产生1 transId:500.但在映射表中此事件为planId 300和400创建两个条目.
>最后一步!在2017-04-10客户卡拒绝他在2017-04-02上的付款,它只下降200美元.这导致了交易表中的逆转交易.然后,此事务将映射到映射表中的最新条目.如映射表中所示,planId:400现在为-200.
以下是创建PaymentPlan和事务表的脚本.
CREATE TABLE #PaymentPlan(PlanId INT ,
PaymentAmount NUMERIC(8,2),
CustomerId INT,
StartDate DATETIME)
INSERT #PaymentPlan(
PlanId ,
PaymentAmount ,
CustomerId ,
StartDate )
VALUES ( 100, 200.00, 100, '2017-01-01'),
( 200, 100.00, 100, '2017-02-01'),
( 300, 100.00, 100, '2017-03-01'),
( 400, 200.00, 100, '2017-04-01')
CREATE TABLE #transaction(TransId INT,
CustomerId INT,
Amount NUMERIC(8,2),
TransactionDate DATETIME,
IsReversed BIT)
INSERT #transaction(
TransId ,
CustomerId ,
Amount ,
TransactionDate ,
IsReversed)
VALUES (100,100,100.00,'2017-01-01',0),
(200,100,100.00,'2017-01-02',0),
(300,100,60.00 ,'2017-01-04',0),
(400,100,40.00, '2017-02-02',0),
(500,100,300.00,'2017-04-02',0),
(600,100,200.00,'2017-04-10',1)
SELECT * FROM #PaymentPlan ORDER BY StartDate
SELECT * FROM #transaction ORDER BY TransactionDate
非常感谢我能得到的任何帮助.
最佳答案 可以将两个表中的金额表示为连续范围,然后找到重叠范围.下一个
snippet可能是更精细版本的基础.
CREATE TABLE #PaymentPlan(PlanId INT,
PaymentAmount NUMERIC(8, 2),
CustomerId INT,
StartDate DATETIME);
INSERT #PaymentPlan(
PlanId,
PaymentAmount,
CustomerId,
StartDate)
VALUES ( 100, 200.00, 100, '2017-01-01'),
( 200, 100.00, 100, '2017-02-01'),
( 300, 100.00, 100, '2017-03-01'),
( 400, 200.00, 100, '2017-04-01');
CREATE TABLE #transaction(TransId INT,
CustomerId INT,
Amount NUMERIC(8,2),
TransactionDate DATETIME,
IsReversed BIT);
INSERT #transaction(
TransId,
CustomerId,
Amount,
TransactionDate,
IsReversed)
VALUES (100,100,100.00,'2017-01-01',0),
(200,100,100.00,'2017-01-02',0),
(300,100,60.00 ,'2017-01-04',0),
(400,100,40.00, '2017-02-02',0),
(500,100,200.00,'2017-04-02',0),
(600,100,300.00,'2017-04-10',1);
WITH
p AS (
SELECT *,
SUM(PaymentAmount) OVER(PARTITION BY CustomerId ORDER BY StartDate) - PaymentAmount LeftBound,
SUM(PaymentAmount) OVER(PARTITION BY CustomerId ORDER BY StartDate) RightBound
FROM #PaymentPlan
),
t AS (
SELECT *,
SUM(Amount) OVER(PARTITION BY CustomerId ORDER BY TransactionDate) - Amount LeftBound,
SUM(Amount) OVER(PARTITION BY CustomerId ORDER BY TransactionDate) RightBound
FROM #transaction
)
SELECT
t.CustomerId, t.TransId, p.PlanId,
p.LeftBound PlanLeftBound, p.RightBound PlanRightBound,
t.LeftBound TransLeftBound, t.RightBound TransRightBound,
t.TransactionDate transDateTime, t.IsReversed
FROM p JOIN t
ON p.CustomerId = t.CustomerId AND
p.LeftBound < t.RightBound AND
p.RightBound > t.LeftBound;