SQL 服务器 - 运行 带结转的总数
SQL Server - Running Total with Carry Forward
在以下方面需要一些帮助:
Table #Data 包含产品超过 5 天的期初和期末库存
Table #BackData 包含一些 post 日期交易
我如何使用 运行 总计更新 table #Data 包括结转
CREATE TABLE #Data (
Prod VARCHAR(20)
,SDate DATE
,OStock INT
,CStock INT
)
CREATE TABLE #BackData (
Prod VARCHAR(20)
,SDate DATE
,CStock INT
)
INSERT INTO #Data
SELECT 'p1', '2016-06-06', 10, 10
UNION ALL
SELECT 'p1', '2016-06-07', 10, 14
UNION ALL
SELECT 'p1', '2016-06-08', 14, 13
UNION ALL
SELECT 'p1', '2016-06-09', 13, 13
UNION ALL
SELECT 'p1', '2016-06-10', 13, 11
INSERT INTO #BackData
SELECT 'p1', '2016-06-06', 2
UNION ALL
SELECT 'p1', '2016-06-07', 4
UNION ALL
SELECT 'p1', '2016-06-09', -1
UNION ALL
SELECT 'p1', '2016-06-10', -2
DROP TABLE #Data
DROP TABLE #BackData
期望的输出:
Prod| SDate |OStock |CStock|
p1 |2016-06-06 |10 |12 |
p1 |2016-06-07 |12 |16 |
p1 |2016-06-08 |16 |16 |
p1 |2016-06-09 |16 |15 |
p1 |2016-06-10 |15 |13 |
编辑
这是我在得到答案之前设法写的,使用了两次更新,因为实际的 table 有太多的列无法在单个查询中使用。
UPDATE D
SET D.CStock = FL.NewCStock
FROM #Data D
INNER JOIN (
SELECT DT.Prod
,DT.SDate
,SUM(IIF(RwNm = 1, DT.CStock, 0) + ISNULL(BD.CStock, 0)) OVER (
PARTITION BY DT.Prod ORDER BY DT.SDate ROWS UNBOUNDED PRECEDING
) NewCStock
FROM (
SELECT Prod
,SDate
,CStock
,ROW_NUMBER() OVER (
PARTITION BY Prod ORDER BY SDate
) AS RwNm
FROM #Data
) DT
LEFT JOIN #BackData BD ON DT.Prod = DT.Prod
AND BD.SDate = DT.SDate
) FL ON D.Prod = FL.Prod
AND D.SDate = FL.SDate
UPDATE D
SET D.OStock = PV.NewOStock
FROM #Data D
INNER JOIN (
SELECT Prod
,SDate
,ISNULL(LAG(CStock) OVER (
PARTITION BY Prod ORDER BY SDate
), CStock) AS NewOStock
FROM #Data
) PV ON D.Prod = PV.Prod
AND D.SDate = PV.SDate
您可以使用以下查询 UPDATE
:
;WITH ToUpdate AS (
SELECT d1.OStock, d1.CStock,
COALESCE(LAG(d2.CStock2) OVER (PARTITION BY d2.Prod
ORDER BY d2.SDate),
d1.OStock) AS OStock2,
d2.CStock2
FROM #Data AS d1
JOIN (
SELECT d.Prod, d.SDate, d.OStock, d.CStock,
COALESCE(t.newCStock,
LAG(t.newCStock) OVER (PARTITION BY d.Prod
ORDER BY d.SDate)) AS CStock2
FROM #Data AS d
LEFT JOIN (
SELECT bd.Prod, bd.SDate,
drn.CStock + SUM(bd.CStock) OVER (PARTITION BY bd.Prod
ORDER BY bd.SDate) AS newCStock
FROM #BackData AS bd
INNER JOIN (
SELECT Prod, CStock,
ROW_NUMBER() OVER (PARTITION BY Prod ORDER BY SDate) AS rn
FROM #Data
) AS drn ON bd.Prod = drn.Prod AND drn.rn = 1
) AS t ON t.Prod = d.Prod AND t.SDate = d.SDate
) AS d2 ON d1.Prod = d2.Prod AND d1.SDate= d2.SDate
)
UPDATE ToUpdate
SET OStock = OStock2,
CStock = CStock2
这看起来非常复杂,但我想不出更简单的事情。
您可以在递归 CTE 的帮助下重建 #Data
table 中的值:
;WITH cte AS (
SELECT top 1 d.Prod,
d.SDate,
d.OStock,
d.OStock + b.CStock as CStock
FROM #Data d
LEFT JOIN #BackData b
ON b.Prod = d.Prod and b.SDate = d.SDate
ORDER BY d.SDate ASC
UNION ALL
SELECT c.Prod,
DATEADD(day,1,c.SDate),
c.CStock,
c.CStock + ISNULL(b.CStock,0)
FROM cte c
INNER JOIN #Data d
ON d.Prod = c.Prod AND d.SDate = DATEADD(day,1,c.SDate)
OUTER APPLY (SELECT CStock FROM #BackData b WHERE b.Prod = d.Prod and b.SDate = d.SDate) as b
)
SELECT *
FROM cte
输出:
Prod SDate OStock CStock
-------------------- ---------- ----------- -----------
p1 2016-06-06 10 12
p1 2016-06-07 12 16
p1 2016-06-08 16 16
p1 2016-06-09 16 15
p1 2016-06-10 15 13
待更新#Data
:
UPDATE d
SET OStock = c.OStock, CStock = c.CStock
FROM #Data d
INNER JOIN cte c
ON c.Prod = d.Prod AND c.SDate = d.SDate
结果不应该是这样的:
Prod SDate OStock CStock
p1 2016-06-06 10 12
p1 2016-06-07 12 20 (#Data CStock 14 + #BakData 2 + 4)
p1 2016-06-08 20 19 (#Data CStock 13 + #BakData 2 + 4)
p1 2016-06-09 19 18 (#Data CStock 13 + #BakData 2 + 4 - 1)
p1 2016-06-10 18 14 (#Data CStock 11 + #BakData 2 + 4 - 1 -2)
这个查询会产生上面的结果
update d
set OStock = d.OStock + a.OAdj,
CStock = d.CStock + a.CAdj
from #Data d
cross apply
(
select OAdj = sum(case when Oflag = 1 then x.CStock else 0 end),
CAdj = sum(x.CStock)
from
(
select *, Oflag = case when x.SDate = d.SDate then 0 else 1 end
from #BackData x
where x.Prod = d.Prod
and x.SDate <= d.SDate
) x
) a
根据您的预期输出,您似乎正在根据 2016-06-06 的数字重新计算每日期初/期末余额
这是一个可以为您提供预期输出的解决方案。
; with
cte as
(
select Prod, SDate, OStock, CStock,
rn = row_number() over (partition by Prod order by SDate)
from #Data
),
adj as
(
select Prod, SDate, CStock
from cte
where rn = 1
union all
select Prod, SDate, CStock
from #BackData
)
update d
set OStock = coalesce(o.OStock, d.OStock),
CStock = c.CStock
from #Data d
cross apply
(
select OStock = sum(x.CStock)
from adj x
where x.Prod = d.Prod
and x.SDate < d.SDate
) o
cross apply
(
select CStock = sum(x.CStock)
from adj x
where x.Prod = d.Prod
and x.SDate <= d.SDate
) c
结果:
p1 2016-06-06 10 12
p1 2016-06-07 12 16
p1 2016-06-08 16 16
p1 2016-06-09 16 15
p1 2016-06-10 15 13
在以下方面需要一些帮助:
Table #Data 包含产品超过 5 天的期初和期末库存
Table #BackData 包含一些 post 日期交易
我如何使用 运行 总计更新 table #Data 包括结转
CREATE TABLE #Data (
Prod VARCHAR(20)
,SDate DATE
,OStock INT
,CStock INT
)
CREATE TABLE #BackData (
Prod VARCHAR(20)
,SDate DATE
,CStock INT
)
INSERT INTO #Data
SELECT 'p1', '2016-06-06', 10, 10
UNION ALL
SELECT 'p1', '2016-06-07', 10, 14
UNION ALL
SELECT 'p1', '2016-06-08', 14, 13
UNION ALL
SELECT 'p1', '2016-06-09', 13, 13
UNION ALL
SELECT 'p1', '2016-06-10', 13, 11
INSERT INTO #BackData
SELECT 'p1', '2016-06-06', 2
UNION ALL
SELECT 'p1', '2016-06-07', 4
UNION ALL
SELECT 'p1', '2016-06-09', -1
UNION ALL
SELECT 'p1', '2016-06-10', -2
DROP TABLE #Data
DROP TABLE #BackData
期望的输出:
Prod| SDate |OStock |CStock|
p1 |2016-06-06 |10 |12 |
p1 |2016-06-07 |12 |16 |
p1 |2016-06-08 |16 |16 |
p1 |2016-06-09 |16 |15 |
p1 |2016-06-10 |15 |13 |
编辑
这是我在得到答案之前设法写的,使用了两次更新,因为实际的 table 有太多的列无法在单个查询中使用。
UPDATE D
SET D.CStock = FL.NewCStock
FROM #Data D
INNER JOIN (
SELECT DT.Prod
,DT.SDate
,SUM(IIF(RwNm = 1, DT.CStock, 0) + ISNULL(BD.CStock, 0)) OVER (
PARTITION BY DT.Prod ORDER BY DT.SDate ROWS UNBOUNDED PRECEDING
) NewCStock
FROM (
SELECT Prod
,SDate
,CStock
,ROW_NUMBER() OVER (
PARTITION BY Prod ORDER BY SDate
) AS RwNm
FROM #Data
) DT
LEFT JOIN #BackData BD ON DT.Prod = DT.Prod
AND BD.SDate = DT.SDate
) FL ON D.Prod = FL.Prod
AND D.SDate = FL.SDate
UPDATE D
SET D.OStock = PV.NewOStock
FROM #Data D
INNER JOIN (
SELECT Prod
,SDate
,ISNULL(LAG(CStock) OVER (
PARTITION BY Prod ORDER BY SDate
), CStock) AS NewOStock
FROM #Data
) PV ON D.Prod = PV.Prod
AND D.SDate = PV.SDate
您可以使用以下查询 UPDATE
:
;WITH ToUpdate AS (
SELECT d1.OStock, d1.CStock,
COALESCE(LAG(d2.CStock2) OVER (PARTITION BY d2.Prod
ORDER BY d2.SDate),
d1.OStock) AS OStock2,
d2.CStock2
FROM #Data AS d1
JOIN (
SELECT d.Prod, d.SDate, d.OStock, d.CStock,
COALESCE(t.newCStock,
LAG(t.newCStock) OVER (PARTITION BY d.Prod
ORDER BY d.SDate)) AS CStock2
FROM #Data AS d
LEFT JOIN (
SELECT bd.Prod, bd.SDate,
drn.CStock + SUM(bd.CStock) OVER (PARTITION BY bd.Prod
ORDER BY bd.SDate) AS newCStock
FROM #BackData AS bd
INNER JOIN (
SELECT Prod, CStock,
ROW_NUMBER() OVER (PARTITION BY Prod ORDER BY SDate) AS rn
FROM #Data
) AS drn ON bd.Prod = drn.Prod AND drn.rn = 1
) AS t ON t.Prod = d.Prod AND t.SDate = d.SDate
) AS d2 ON d1.Prod = d2.Prod AND d1.SDate= d2.SDate
)
UPDATE ToUpdate
SET OStock = OStock2,
CStock = CStock2
这看起来非常复杂,但我想不出更简单的事情。
您可以在递归 CTE 的帮助下重建 #Data
table 中的值:
;WITH cte AS (
SELECT top 1 d.Prod,
d.SDate,
d.OStock,
d.OStock + b.CStock as CStock
FROM #Data d
LEFT JOIN #BackData b
ON b.Prod = d.Prod and b.SDate = d.SDate
ORDER BY d.SDate ASC
UNION ALL
SELECT c.Prod,
DATEADD(day,1,c.SDate),
c.CStock,
c.CStock + ISNULL(b.CStock,0)
FROM cte c
INNER JOIN #Data d
ON d.Prod = c.Prod AND d.SDate = DATEADD(day,1,c.SDate)
OUTER APPLY (SELECT CStock FROM #BackData b WHERE b.Prod = d.Prod and b.SDate = d.SDate) as b
)
SELECT *
FROM cte
输出:
Prod SDate OStock CStock
-------------------- ---------- ----------- -----------
p1 2016-06-06 10 12
p1 2016-06-07 12 16
p1 2016-06-08 16 16
p1 2016-06-09 16 15
p1 2016-06-10 15 13
待更新#Data
:
UPDATE d
SET OStock = c.OStock, CStock = c.CStock
FROM #Data d
INNER JOIN cte c
ON c.Prod = d.Prod AND c.SDate = d.SDate
结果不应该是这样的:
Prod SDate OStock CStock
p1 2016-06-06 10 12
p1 2016-06-07 12 20 (#Data CStock 14 + #BakData 2 + 4)
p1 2016-06-08 20 19 (#Data CStock 13 + #BakData 2 + 4)
p1 2016-06-09 19 18 (#Data CStock 13 + #BakData 2 + 4 - 1)
p1 2016-06-10 18 14 (#Data CStock 11 + #BakData 2 + 4 - 1 -2)
这个查询会产生上面的结果
update d
set OStock = d.OStock + a.OAdj,
CStock = d.CStock + a.CAdj
from #Data d
cross apply
(
select OAdj = sum(case when Oflag = 1 then x.CStock else 0 end),
CAdj = sum(x.CStock)
from
(
select *, Oflag = case when x.SDate = d.SDate then 0 else 1 end
from #BackData x
where x.Prod = d.Prod
and x.SDate <= d.SDate
) x
) a
根据您的预期输出,您似乎正在根据 2016-06-06 的数字重新计算每日期初/期末余额
这是一个可以为您提供预期输出的解决方案。
; with
cte as
(
select Prod, SDate, OStock, CStock,
rn = row_number() over (partition by Prod order by SDate)
from #Data
),
adj as
(
select Prod, SDate, CStock
from cte
where rn = 1
union all
select Prod, SDate, CStock
from #BackData
)
update d
set OStock = coalesce(o.OStock, d.OStock),
CStock = c.CStock
from #Data d
cross apply
(
select OStock = sum(x.CStock)
from adj x
where x.Prod = d.Prod
and x.SDate < d.SDate
) o
cross apply
(
select CStock = sum(x.CStock)
from adj x
where x.Prod = d.Prod
and x.SDate <= d.SDate
) c
结果:
p1 2016-06-06 10 12
p1 2016-06-07 12 16
p1 2016-06-08 16 16
p1 2016-06-09 16 15
p1 2016-06-10 15 13