是否有一种简单的方法可以跨多行传播值?
例如,我的表包含
Type Invoiced Paid Current Charge 100 0 100 Charge 100 0 100 Charge 100 0 100 Payment 0 250 0 Payment 0 25 0
以这种方式导入数据,但我需要根据同时导入的付款交易,在Current
和Paid
列填充该交易的任何内容。
是否有一种简单的方法来编写查询以确定每条记录的Current
列的余额?
例如,250将对前两个记录应用100,对接下来的两个应用50,并且25将应用于最后一个,因此更新表中的Current
余额后的最终结果应该是:
Type Invoiced Paid Current Charge 100 100 0 Charge 100 100 0 Charge 100 75 25 Payment 0 250 0 Payment 0 25 0
理想情况下,我希望使用单个查询来执行此操作,而不是使用游标单独处理每个项目。我一直在尝试使用Row_Number()函数并加入两个子查询,但我知道我在这里遗漏了一些东西
这是我的第一次尝试,这导致获得当前余额的累计
;with cte(invoiced, paid, current)
as (
select invoiced, paid, current
, row_number() over (order by datecreated)
from mytable
)
select t1.invoiced, t1.paid, sum(t2.invoiced - t2.paid) as [current]
from cte as t1
join cte as t2 on t1.number = t2.number and t2.rownum <= t1.rownum
group by t1.uid, t1.number, t1.rownum
order by t1.rownum
结果:
Invoiced Paid Current 100 0 100 100 0 200 100 0 300 0 250 50 0 25 25
我确定有办法做到这一点,但现在我的大脑似乎正在罢工,并拒绝提出解决方案。
答案 0 :(得分:3)
我想我找到了解决方案
首先,我不需要将付费交易与发票交易相关联,因此我只需要所有付款的总和
select accountid, sum(paid)
from mytable
where type = 'Payment'
group by accountid
然后我需要将此值应用于每个记录,直到运行总计变得大于支付总额。
要做到这一点,我修改了我的运行总查询,因此它只汇总费用,而不是将费用和付款相加
;with cte(id, accountid, invoiced, paid, current)
as (
select id, accountid, invoiced, paid, current
, row_number() over (order by datecreated)
from mytable
where type = 'Charge'
)
select t1.id, t1.accountid, t1.invoiced, sum(t2.invoiced) as [runningTotalOfCharges]
from cte as t1
join cte as t2 on t1.number = t2.number and t2.rownum <= t1.rownum
group by t1.id, t1.accountid, t1.invoiced
并将其加入到付款查询中,所以现在我有一堆行包含总付款金额,直到该记录的运行总费用以及当前记录的费用金额。
从那里开始,我只需要一个CASE
声明来确定费用是完全支付,部分支付还是根本不支付,并使用一点数学来计算Paid
和{ {1}}记录
Current
最终的结果就是我想要的。只需通过select charged.Id, charged.AccountId, charged.Invoiced
-- Use Case statements to determine if this payment is fully paid, partially paid,
-- or not paid at all, then determine Current and Paid based on that
, case when totalpaid - runningtotal >= 0 then invoiced
when invoiced > abs(totalpaid - runningtotal) then invoiced + totalpaid - runningtotal
else 0 end as [Paid]
, case when totalpaid - runningtotal >= 0 then 0
when invoiced > abs(totalpaid - runningtotal) then abs(totalpaid - runningtotal)
else invoiced end as [Current]
from
(
-- Running total query from above
select t1.id, t1.accountid, t1.invoiced, sum(t2.invoiced) as [runningtotal]
from cte as t1
join cte as t2 on t1.number = t2.number and t2.rownum <= t1.rownum
group by t1.id, t1.accountid, t1.invoiced
) as charged
inner join (
-- Total Paid query from above
select accountid, sum(paid) as totalpaid
from mytable
where type = 'Payment'
group by accountid
) as paid on charged.number = paid.number
列将其加入实际数据表,然后更新Id
和Paid
值:)
Id AccountId Invoiced Paid Current 1 1 100 100 0 2 1 100 100 0 3 1 100 75 25
答案 1 :(得分:0)
您可以计算付费和当前列的运行总计和总和,然后执行一些数学计算以获取当前列值。我尝试了一下,但是在数学方面陷入了困境,想出了最终的价值观。这不是一种简单的方法,但它是一种方式。
DECLARE @myTable TABLE
(
[TranId] INT,
[Type] VARCHAR(10),
[Invoiced] INT,
[Paid] INT,
[Current] INT,
[SumPaid] INT,
[SumCurrent] INT,
[RunningPaid] INT,
[RunningCurrent] INT
)
INSERT INTO @myTable SELECT 1, 'Charge', 100, 0, 100, null, null, null, null
INSERT INTO @myTable SELECT 2, 'Charge', 100, 0, 100, null, null, null, null
INSERT INTO @myTable SELECT 3, 'Charge', 100, 0, 100, null, null, null, null
INSERT INTO @myTable SELECT 4, 'Paid', 0, 250, 0, null, null, null, null
INSERT INTO @myTable SELECT 5, 'Paid', 0, 25, 0, null, null, null, null
UPDATE @myTable SET SumPaid = (SELECT SUM([Paid]) FROM @myTable)
UPDATE @myTable SET SumCurrent = (SELECT SUM([Current]) FROM @myTable)
UPDATE @myTable
SET
[RunningPaid] = full_running_total_set.[RunningPaid],
[RunningCurrent] = full_running_total_set.[RunningCurrent]
FROM @myTable
INNER JOIN
(
SELECT
TranId1,
SUM([Paid]) AS [RunningPaid],
SUM([Current]) AS [RunningCurrent]
FROM
(
SELECT
set2.[Paid],
set2.[Current],
set1.[TranId] AS [TranId1],
set2.[TranId] AS [TranId2]
FROM @myTable set1
INNER JOIN @myTable set2
ON set1.[TranId] >= set2.[TranId]
)running_total_set
GROUP BY [TranId1]
)full_running_total_set
ON [TranId] = full_running_total_set.[TranId1]
SELECT * FROM @myTable