Pet*_*ock 7 sql-server-2008-r2
我有一个表,其中 RowNumber 是本质。它有一系列客户端,以及该客户端的运行总数 - 每次客户端更改时都会重置。例如
client rownr amount runtotal
Company A 1 1.00 1.00
Company A 2 1.00 2.00 1+1 = 2
Company A 3 5.00 7.00 2+5 = 7
Company B 4 3.00 3.00 Reset Because Customer B <> Previous Row Customer A
Company A 5 1.00 1.00 Reset Because Customer A <> Previous Row Customer B
Company B 6 2.00 2.00 Reset Because Customer B <> Previous Row Customer A
Company B 7 1.00 3.00 2+1 = 3
Company B 8 5.00 8.00 3+5 = 8
Run Code Online (Sandbox Code Playgroud)
我尝试使用分区,但它总是将客户端 A 和客户端 B 组合在一起 - 它删除了行号的关键部分。
请问有什么帮助吗?
drop table #Checks
CREATE TABLE #Checks
(
Client VARCHAR(32),
RowNr int,
Amount DECIMAL(12,2),
RunTotal DECIMAL(12,2),
Part int
);
INSERT #Checks(Client, RowNr, Amount)
SELECT 'Company A', '1', 1
UNION ALL SELECT 'Company A', '2', 1
UNION ALL SELECT 'Company A', '3', 5
UNION ALL SELECT 'Company B', '4', 3
UNION ALL SELECT 'Company A', '5', 1
UNION ALL SELECT 'Company B', '6', 2
UNION ALL SELECT 'Company B', '7', 1
UNION ALL SELECT 'Company B', '8', 5;
-- gets the first entries per client - these amounts are
-- the base amounts and the other entries are tallied up
with cte as (
select
c1.client
, c1.amount
, c1.rowNr
, case when c1.client <> c2.client then c1.amount else null end amt
from #Checks as c1
left join #Checks as C2 on c1.rownr = (c2.rownr + 1)
)
select
client
, rownr
, amount
, case when isnull(amt,0) > 0 then amt else total end as runtotal
from cte
cross apply (
select
sum(x.amount) as Total
from cte as x
where x.rownr <= cte.rownr and cte.client = x.client
) as rt
;
Drop table #Checks
Run Code Online (Sandbox Code Playgroud)
这应该做你想做的:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY Client ORDER BY RowNr)
FROM #Checks
), CTE2 AS
(
SELECT *,
RN2 = RowNr - RN
FROM CTE
)
SELECT A.Client, A.RowNr, A.Amount, B.RunTotal
FROM CTE2 A
CROSS APPLY (SELECT SUM(Amount) RunTotal
FROM CTE2
WHERE Client = A.Client
AND RN2 = A.RN2
AND RowNr <= A.RowNr) B
ORDER BY RowNr
Run Code Online (Sandbox Code Playgroud)
结果:
?????????????????????????????????????????
? Client ? RowNr ? Amount ? RunTotal ?
?????????????????????????????????????????
? Company A ? 1 ? 1.00 ? 1.00 ?
? Company A ? 2 ? 1.00 ? 2.00 ?
? Company A ? 3 ? 5.00 ? 7.00 ?
? Company B ? 4 ? 3.00 ? 3.00 ?
? Company A ? 5 ? 1.00 ? 1.00 ?
? Company B ? 6 ? 2.00 ? 2.00 ?
? Company B ? 7 ? 1.00 ? 3.00 ?
? Company B ? 8 ? 5.00 ? 8.00 ?
?????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
怎么样:
SELECT c.client, c.rownr, c.amount
, runtotal = SUM(e.amount)
FROM #Checks c
JOIN #Checks e ON e.RowNr <= c.RowNr AND e.Client = c.Client -- row from c (note <= not <) and all earlier rows
LEFT OUTER JOIN -- rows between with different cli
#Checks d ON d.RowNr < c.RowNr AND d.RowNr > e.RowNr AND d.Client<>c.Client
WHERE d.RowNr IS NULL -- drop where there is a row between the one from c and the one from e with different client
GROUP BY c.client, c.rownr, c.amount
ORDER BY c.rownr
Run Code Online (Sandbox Code Playgroud)
如果客户端上有索引,那么第一个连接在大型数据集上可能会很昂贵(为了提高效率,您需要在客户端、rownr 上有一个索引,在 rownr 上有一个索引(尽管我假设这将是您的 PK,这意味着索引已经))不是很有选择性(如果客户端列中的数据种类及其相对于 rown 的分布意味着基于它的索引不是很有选择性,那么第一个连接将与笛卡尔积一样接近没有机会)。