SQL如何在满足阈值/条件之前对同一列的值求和?

时间:2016-06-16 17:13:52

标签: sql sql-server tsql

编辑 - 我正在使用MSSQL Server 2005 - SP4(9.0.5000)

表格中有3列 - 客户ID,订单号,付款日期和付款。当用户进行付款时,它会使用客户ID记录数据,增加订单号(因此第一笔付款为1,第二笔付款为2等),并且具有日期和付款金额。

我只想查询所有首笔付款,直到总付款金额达到阈值/条件100为止。

首先,我尝试使用sum()来查看是否有些东西会神奇地出现在我的脑海中 - 但总数是我知道怎么做的:

select CustomerID, Order, sum(Payment) as FirstFullPayment
from #temp
group by CustomerID

然后我尝试制作两个不同的临时表 - 未完成付款的#up和完成付款的#fp。我的想法是,我可以将已确认的> 100付款放入#fp,并将已确认的未完成付款放入#up中,如下所示:

select * into #fp
from #temp
where Order = 1 and Payment >= 100

select * into #up
from #temp
where Order = 1 and Payment < 100

然后我可以按顺序加入#up和#temp,其中Order = 2,3,4等,在#up中添加付款,直到它们是&gt; = 100,然后将它们插入#fp

唯一的问题是我知道这是一个非常糟糕和迂回的方法,必须有一个更好,更简单的方法来做到这一点!提前谢谢!

3 个答案:

答案 0 :(得分:3)

您可以使用运行总和并按您的条件选择行:&lt; = 100

select top 1 * from 
    (
    select CustomerID,  
                (
                SELECT SUM(b.payment)
                           FROM #temp b
                           WHERE a.customerid=b.customerID and  b.[order] <= a.[order]) as FirstFullPayment
    from #temp a
    --where customerid=yourCustomerId
    )runningsums
where runningsums.FirstFullPayment<=100
order by runningsums.FirstFullPayment desc

答案 1 :(得分:1)

我假设没有任何付款可以是负数,因此累积金额也将是一个增加的系列(单调)。如果您想要累计总数和订单数超过阈值,这是实现此目的的一种方法:

select CustomerID, min(OrderNumber), min(CumulativePayments)
from
(
    select
        CustomerID, OrderNumber,
        (
            select sum(t2.Payment) from T t2
            where t2.CustomerID = t.CustomerID and t2.OrderNumber <= t.OrderNumber
        ) as CumulativePayments
   from T t
) cp
where CumulativePayments >= 100
group by CustomerID

编辑:如果您需要所有数据和行最多阈值点:

select * from T t
where OrderNumber <=
(
    select min(OrderNumber)
    from
    (
        select
            OrderNumber,
            (
                select sum(t3.Payment) from T t3
                where t3.CustomerID = t2.CustomerID and t3.OrderNumber <= t2.OrderNumber
            ) as CumulativePayments
        from T t2
        where t2.CustomerID = t.CustomerID
    ) cp
    where CumulativePayments >= 100
)

这些方法不依赖row_number()sum() over (...)top n...order by

答案 2 :(得分:1)

这是使用公共表表达式的另一种方法(随SQL 2005引入):

;WITH cteBaseline
 as (--  For each customer, for each order, get sum of payments for all
     --  orders less than or equal to "this" order, where the total is
     --  within the desired range
     select
        te.CustomerId
       ,te.Order
       ,sum(subset.Payment) TotalPayment
      from #temp te
       inner join #temp subset
        on subset.CustomerId <= te.CustomerId
      group by
        te.CustomerId
       ,te.Order
      having sum(subset.Payment) < 100  --  Make this a parameter to control the "breakpoint"
     )
--  Get the "last" row
select
   cte.CustomerId
  ,cte.Order
  ,cte.TotalPayment
 from cteBaseline cte
  inner join (--  get the "last" row, the one with the largest TotalPayment
              select
                 CustomerId
                ,max(Order)
               from cteBaseline
               group by CustomerId) xx
   on xx.CustomerId = cte.CustomerId
    and xx.Order = cte.Order

您想要仔细检查语法。此外,根据表格大小和索引,这可能表现不佳,因为有很多加入。