【问题标题】:SQL Server Calculate cumulative sum / conditional running total depending on different flagsSQL Server 根据不同的标志计算累积总和/条件运行总和
【发布时间】:2018-05-30 19:21:18
【问题描述】:

我在 SQL Server 中有一个表,其中的数据类似于此示例。

ID  Flag    Art.No  Amount
1   U   A1000   -100
2   U   B2000   -5
3   V   B2000   900
4   U   B2000   -10
5   I   B2000   50
6   U   B2000   -20
7   U   A1000   -50
8   I   A1000   1000
9   V   A1000   3600
10  U   A1000   -500
11  U   A1000   -100
12  U   A1000   -2000
13  I   A1000   2000
14  U   A1000   -1000
15  I   C3000   10000
16  U   C3000   -4000
17  U   B2000   -5
18  U   B2000   -5
19  I   B2000   40
20  V   B2000   200
21  U   A1000   -500
22  U   B2000   -50
23  U   C3000   -1000

我想根据交易计算累计值。我的问题是该表包含 3 种类型的事务。

  1. 标志 U - 销售
  2. 标志 I - 进货
  3. 标志 V - 盘点

当标志 U 和 I 出现时,数量代表变化 当Flag V出现时,金额代表盘点时的总金额

换句话说,我想为每个 unice Art.No 找到最新的 V 事务,然后添加或减去 U 和 I 事务以获得每一行的累积和。 如果没有 V-transaction 则遍历整个数据集。

我已经为每个 Art.No 制作了具有预期结果的示例

A1000

ID  Flag    Art.No  Amount  A1000 Example
1   U   A1000   -100    
7   U   A1000   -50 
8   I   A1000   1000    
9   V   A1000   3600    3600
10  U   A1000   -500    3100
11  U   A1000   -100    3000
12  U   A1000   -2000   1000
13  I   A1000   2000    3000
14  U   A1000   -1000   2000
21  U   A1000   -500    1500

B2000

ID  Flag    Art.No  Amount  B2000 Example
2   U   B2000   -5  
3   V   B2000   900 
4   U   B2000   -10 
5   I   B2000   50  
6   U   B2000   -20 
17  U   B2000   -5  
18  U   B2000   -5  
19  I   B2000   40  
20  V   B2000   200 200
22  U   B2000   -50 150

C3000

ID  Flag    Art.No  Amount  C3000 Example
15  I   C3000   10000   10000
16  U   C3000   -4000   6000
23  U   C3000   -1000   5000

编辑: 为了在数据集中获得更多历史记录,最好在最近的 V 交易之前有这样的值

B2000

ID  Flag    Art.No  Amount  B2000 Example
2   U   B2000   -5  150
3   V   B2000   900 140
4   U   B2000   -10 140
5   I   B2000   50  190
6   U   B2000   -20 170
17  U   B2000   -5  165
18  U   B2000   -5  160
19  I   B2000   40  200
20  V   B2000   200 200
22  U   B2000   -50 150

考虑每个 I 和 U 事务但忽略 V 事务。

【问题讨论】:

  • 请将一些数据和您的查询添加到 dbfiddle:dbfiddle.uk 以便我们提供更好的帮助(只需在您第一次运行 fiddle 后粘贴地址)
  • 我并没有完全遵循所需的逻辑。在 A 示例中,在收到第一个 V 之后只有一个值。但在 B 示例中,ID 3 处的 V 被忽略,只有 ID 20 处的 V 开始计数。在 C 示例中,根本没有 V,但您有值。请说清楚?另外,我们是否可以假设ID增加是用于处理的顺序?
  • 我认为您可以按文章分组然后按标志进行汇总,无需进行测试我无法确定要发布的查询
  • ID 将随着每笔新交易而增加。 Art.No 可能很旧,并且经过了多次盘点,其中 ID 最高的那个是最近总计数的那个。
  • 这里有一个 dbfiddle 链接dbfiddle.uk/…

标签: sql sql-server tsql


【解决方案1】:
with cte as
 (
   select *,
      -- find the latest 'V' ID per ArtNo
      max(case when Flag = 'V' then ID end) 
      over (partition by ArtNo) as Last_V_ID
   from myTable
 )
select *,
   -- cumulative sum, but ignore all rows before the latest 'V' ID
   -- includes rows when there's no 'V' ID for this ArtNo
   sum(case when ID < Last_V_ID then null else Amount end)
   over (partition by ArtNo
         order by ID
         rows unbounded preceding)
from cte
order by ArtNo, ID

Fiddle

编辑:

要包含上次盘点之前的数据并忽略所有以前的盘点,您可以使用以下方法:

with cte as
 (
   select *,
      -- find the latest 'V' ID per ArtNo
      max(case when Flag = 'V' then ID end) 
      over (partition by ArtNo) as Last_V_ID
   from [dbo].[Warehouse]
 )
select *,
   -- cumulative sum, but ignore all rows before the latest 'V' ID
   -- includes rows when there's no 'V' ID for this ArtNo
   sum(case when ID < Last_V_ID then null else Amount end)
   over (partition by ArtNo
         order by ID
         rows unbounded preceding)
   -- calculate in-stock based on last 'V' ID, discarding all previous 'V' rows
  ,sum(case when (ID < Last_V_ID and Flag <> 'V')  then -Amount 
            when ID = Last_V_ID then Amount 
       end)
   over (partition by ArtNo
         order by ID 
         rows between 1 following and unbounded following)
from cte
order by ArtNo, ID

这两种计算是互斥的,因此您可以使用 COALESCE 轻松组合它们。

Fiddle

【讨论】:

  • 我已对关于旧交易的最初问题进行了编辑。我会尝试小提琴并发布我的进度链接。
  • 哇,这太棒了。我希望我能投不止一个赞成票。对于组合查询,请参阅:dbfiddle.uk/…
最近更新 更多