如何根据列值

时间:2017-03-21 15:02:27

标签: sql-server sql-server-2012

我发现了这个:How to group/rank records based on a changing value of a column?这与我正在寻找的相似,但并不像我需要的那样工作。

基本上,我的数据看起来像这样:

Id          UserId      Type            Amount   RunningTotal
----------- ----------- --------------- -------- -------------
2759        750         charge          -50.00   -50.00
2760        750         charge          -125.00  -175.00
4308        750         paymentGC       50.00    -125.00
4309        750         paymentGC       125.00   0.00
19916       750         charge          -1.00    -1.00
19917       750         creditRefund    124.00   123.00
23238       750         paymentCC       50.00    173.00
23239       750         paymentCC       125.00   298.00
23240       750         charge          -50.00   248.00
23241       750         charge          -125.00  123.00
41300       750         creditRefund    125.00   248.00
42054       750         paymentCC       50.00    298.00
42055       750         paymentCC       125.00   423.00
42056       750         charge          -50.00   373.00
42057       750         charge          -125.00  248.00
56983       750         creditRefund    125.00   373.00
63083       750         paymentCC       50.00    423.00
63084       750         paymentCC       125.00   548.00
63085       750         charge          -50.00   498.00
63086       750         charge          -125.00  373.00
80829       750         creditRefund    125.00   498.00

这很有效,但每次遇到RunningTotal时我都需要重置creditRefund。我查看了使用OVER(ROWS BETWEEN CURRENT ROW AND x FOLLOWING),但这不起作用,因为它们之间可以有任意数量的行,具体取决于帐户上发生的情况。

所以我需要它看起来更像这样:

Id          UserId      Type            Amount   RunningTotal
----------- ----------- --------------- -------- -------------
2759        750         charge          -50.00   -50.00
2760        750         charge          -125.00  -175.00
4308        750         paymentGC       50.00    -125.00
4309        750         paymentGC       125.00   0.00
19916       750         charge          -1.00    -1.00
19917       750         creditRefund    124.00   123.00
23238       750         paymentCC       50.00    50.00
23239       750         paymentCC       125.00   175.00
23240       750         charge          -50.00   125.00
23241       750         charge          -125.00  0.00
41300       750         creditRefund    125.00   125.00
42054       750         paymentCC       50.00    50.00
42055       750         paymentCC       125.00   175.00
42056       750         charge          -50.00   125.00
42057       750         charge          -125.00  0.00
56983       750         creditRefund    125.00   125.00
63083       750         paymentCC       50.00    50.00
63084       750         paymentCC       125.00   175.00
63085       750         charge          -50.00   125.00
63086       750         charge          -125.00  0.00
80829       750         creditRefund    125.00   125.00

这是我到目前为止所得到的:

SELECT Id, UserId, [Type], RunningTotal = SUM(Amount) OVER (ORDER BY t.Id)
FROM Transactions
WHERE UserId = @User

关于如何实现这一目标的任何想法?我觉得我需要以某种方式对它们进行分组,以便运行总重置并且我可以使用PARTITION BY子句。但是我无法让它发挥作用。如果它归结为它,我想我可以在从C#返回之后在C#中完成它,但我宁愿不必这样做。

2 个答案:

答案 0 :(得分:2)

使用子查询来标识每个组的开始grp(使用lag()仅在有顺序PaymentCC时启动组一次,而另一个用于生成组编号{ {1}},然后使用sumgrp作为sumgrp的分区:

RunningTotal

rextester 演示http://rextester.com/POX67852

返回:

select 
    Id
  , UserId
  , Type
  , Amount
  , RunningTotal = sum(amount) over (partition by userid, sumgrp order by id)
  , desired_result
from (
  select *
      , sumgrp = sum(grp) over (
          partition by userid 
          order by id
        )
  from (
    select * 
      , grp = (case when type='PaymentCC' 
              and isnull(lag(type) over (
                partition by userid 
                order by id
                ),'') <> 'PaymentCC' 
            then 1 
          else 0 end) 
    from Transactions
    ) as g
) as s
where UserId = 750

答案 1 :(得分:0)

您可以使用总计

中的大小写重置
;with cte as (
select *, sum(amount) over(order by id) RowSum, case when [Type]='creditRefund' Then 1 else 0 end as Num from #yourtable
)
, cte2 as ( SELECT *, sum(num) over (order by id) ResetFlag from cte )
select *, sum(case when [Type]='creditRefund' Then 0 else Amount END) over(partition by ResetFlag order by id) from cte2


create table #yourtable ( id int, userid int, type varchar(20), amount float)

insert into #yourtable (
Id      ,    UserId  ,    Type      ,      Amount ) values
----------- ----------- --------------- -------- -------------
 (2759  ,      750      ,   'charge      ', -50.00  )
,(2760  ,      750      ,   'charge      ', -125.00 )
,(4308  ,      750      ,   'paymentGC   ', 50.00   )
,(4309  ,      750      ,   'paymentGC   ', 125.00  )
,(19916 ,      750      ,   'charge      ', -1.00   )
,(19917 ,      750      ,   'creditRefund', 124.00  )
,(23238 ,      750      ,   'paymentCC   ', 50.00   )
,(23239 ,      750      ,   'paymentCC   ', 125.00  )
,(23240 ,      750      ,   'charge      ', -50.00  )
,(23241 ,      750      ,   'charge      ', -125.00 )
,(41300 ,      750      ,   'creditRefund', 125.00  )
,(42054 ,      750      ,   'paymentCC   ', 50.00   )
,(42055 ,      750      ,   'paymentCC   ', 125.00  )
,(42056 ,      750      ,   'charge      ', -50.00  )
,(42057 ,      750      ,   'charge      ', -125.00 )
,(56983 ,      750      ,   'creditRefund', 125.00  )
,(63083 ,      750      ,   'paymentCC   ', 50.00   )
,(63084 ,      750      ,   'paymentCC   ', 125.00  )
,(63085 ,      750      ,   'charge      ', -50.00  )
,(63086 ,      750      ,   'charge      ', -125.00 )
,(80829 ,      750      ,   'creditRefund', 125.00  )