使用分组累积先前的行

时间:2018-03-22 03:22:10

标签: sql sql-server tsql

我在MS SQL Server上有这个表

Customer    Month    Amount
-----------------------------
Tom         1        10
Kate        1        60
Ali         1        70
Tom         2        50
Kate        2        40
Tom         3        80
Ali         3        20

我希望select能够累积每个月的客户

Customer    Month    Amount
-----------------------------
Tom         1        10
Kate        1        60
Ali         1        70
Tom         2        60
Kate        2        100
Ali         2        70
Tom         3        140
Kate        3        100
Ali         3        90

注意到Ali没有2个月的数据 凯特没有3个月的数据

我已经完成了,但问题是,对于每个客户缺少的月份,没有数据显示 即凯特必须在第3个月有100个金额 和阿里必须在第二个月有70个金额

declare @myTable as TABLE   (Customer varchar(50), Month int, Amount int)
;

INSERT INTO @myTable
    (Customer, Month, Amount)
VALUES
    ('Tom', 1, 10),
    ('Kate', 1, 60),
    ('Ali', 1, 70),
    ('Tom', 2, 50),
    ('Kate', 2, 40),
    ('Tom', 3, 80),
    ('Ali', 3, 20);


select * from @myTable


select
    SUM(b.Amount),a.Customer, a.Month
from
    @myTable a
        inner join
    @myTable b
        on a.Customer = b.Customer and 
            a.Month >= b.Month
group by
    a.Customer, a.Month

9 个答案:

答案 0 :(得分:3)

使用窗口功能

select Customer, Month,
       sum(Amount) over (partition by customer order by month) Amount
from table t

因此,您需要某种look up表,这些表可能与客户有关。

with cte as
(
     select * from (
        select Customer from table 
        group by Customer)c 
     cross join (values (1),(2),(3))a(Months) 
) -- look-up table 

select c.Customer, c.Months, 
       sum(t.Amount) over (partition by c.Customer order by c.Months) Amount 
from cte c left join table t 
      on t.Month = c.Months and t.Customer  = c.Customer

结果:

Customer Months Amount
Tom      1      10
Kate     1      60
Ali      1      70
Tom      2      60
Ali      2      70
Kate     2      100
Ali      3      90
Kate     3      100
Tom      3      140

答案 1 :(得分:2)

with cte as
(select *
 from
  (select distinct customer from myTable ) c
  cross join ( values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) t(month))

select cte.customer, cte.month, 
sum(myTable.amount) over (partition by cte.customer order by cte.month) as cumamount
from cte left join myTable
on cte.customer = myTable.customer and cte.month = myTable.month
order by  cte.month, cte.customer desc

答案 2 :(得分:1)

您是否希望每个月为每位客户获得金额,客户在该月的交易情况如何? 在下面的脚本中,如果您有一个customer表,则可以加入customer表,不需要使用(SELECT DISTINCT Customer FROM @myTable)

declare @myTable as TABLE   (Customer varchar(50), Month int, Amount int);
INSERT INTO @myTable(Customer, Month, Amount)
VALUES
    ('Tom', 1, 10),
    ('Kate', 1, 60),
    ('Ali', 1, 70),
    ('Tom', 2, 50),
    ('Kate', 2, 40),
    ('Tom', 3, 80),
    ('Ali', 3, 20),
    ('Jack', 3, 90);

    SELECT c.Customer,sv.number AS Month ,SUM(CASE WHEN t.Month<=sv.number THEN t.Amount ELSE 0 END ) AS Amount
    FROM master.dbo.spt_values AS sv 
    INNER JOIN (SELECT DISTINCT Customer FROM @myTable) AS c ON 1=1
    LEFT JOIN @myTable AS t ON t.Customer=c.Customer
    WHERE sv.type='P' AND sv.number BETWEEN 1 AND MONTH(GETDATE())
    GROUP BY sv.number,c.Customer
    ORDER BY c.Customer,sv.number
----------

Customer                                           Month       Amount
-------------------------------------------------- ----------- -----------
Ali                                                1           70
Ali                                                2           70
Ali                                                3           90
Jack                                               1           0
Jack                                               2           0
Jack                                               3           90
Kate                                               1           60
Kate                                               2           100
Kate                                               3           100
Tom                                                1           10
Tom                                                2           60
Tom                                                3           140

答案 3 :(得分:1)

试试这个表名是“a”。 使用Cte和子查询的组合。在MSSQL2008R2中试过它

 with cte as
(
 select * from (
    select Customer from a 
    group by Customer)c 
 cross join (values (1),(2),(3),(4),(5),(6),(7),(8),(9), (10),(11),(12))a(Months) 
) 
select  Customer,Months,

(select  SUM(total) from 
(select customer , month , sum(amount)as total from a   group by  customer, 
month) as GroupedTable
where GroupedTable.customer= cte.customer and  GroupedTable.month<= cte.Months) as total
  from cte
Group by  Customer,Months
order by Customer,Months

答案 4 :(得分:1)

试试这个:         create table #tmp(Customer VARCHAR(10),[month] INT,Amount INT)

    INSERT INTO #tmp
    SELECT 'Tom',1,10
    union all
    SELECT 'Kate',1,60
    union all
    SELECT 'Ali',1,70
    union all
    SELECT 'Tom',2,50
    union all
    SELECT 'Kate',2,40
    union all
    SELECT 'Tom',3,80
    union all
    SELECT 'Ali',3,20

    ;WITH cte1 AS (
        SELECT [month], ROW_NUMBER() OVER(order by [month] desc) rn 
        FROM (SELECT DISTINCT [month] as [month] FROM #tmp) a
        )
    , cte2 AS (
        SELECT customer, ROW_NUMBER() OVER(order by customer desc) rn 
        FROM (SELECT DISTINCT customer as customer FROM #tmp) b
        )


    SELECT t2.Customer,t2.[month],ISNULL(t1.Amount,0) As Amount 
    into #tmp2
    from #tmp t1
    RIGHT JOIN 
    (select [month],customer from cte1 
    cross apply 
    cte2) t2 ON t1.customer=t2.customer and t1.[month]=t2.[month] 
    order by t2.[month]


    SELECT Customer,[Month] ,SUM (Amount) OVER(partition by customer order by customer ROWS UNBOUNDED PRECEDING ) as Amount 
    FROM #tmp2
    order by [month]

    drop table #tmp
    drop table #tmp2

答案 5 :(得分:1)

要清楚(在答案Amount和AmountSum中)

DECLARE @myTable TABLE(Customer varchar(50), Month int, Amount int);

INSERT INTO @myTable(Customer, Month, Amount)
VALUES
    ('Tom', 1, 10),
    ('Kate', 1, 60),
    ('Ali', 1, 70),
    ('Tom', 2, 50),
    ('Kate', 2, 40),
    ('Tom', 3, 80),
    ('Ali', 3, 20);


DECLARE @FullTable TABLE(Customer varchar(50), Month int, Amount int);

INSERT INTO @FullTable(Customer, Month, Amount)
SELECT c.Customer, m.Month, ISNULL(mt.Amount, 0)
FROM (SELECT DISTINCT [Month] FROM @myTable) AS m
CROSS JOIN (SELECT DISTINCT Customer FROM @myTable) AS c
LEFT JOIN @myTable AS mt ON m.Month = mt.Month AND c.Customer = mt.Customer


SELECT t1.Customer, t1.Month, t1.Amount, (t1.Amount + ISNULL(t2.sm, 0)) AS AmountSum
FROM @FullTable AS t1
CROSS APPLY (SELECT SUM(Amount) AS sm FROM @FullTable AS t WHERE t.Customer = t1.Customer AND t.Month < t1.Month) AS t2
ORDER BY Month, Customer

答案 6 :(得分:1)

我认为这可以做你想要的事情

declare @myTable as TABLE   (Customer varchar(50), Month int, Amount int);
INSERT INTO @myTable (Customer, Month, Amount)
VALUES
    ('Tom', 1, 10),
    ('Kate', 1, 60),
    ('Ali', 1, 70),
    ('Tom', 2, 50),
    ('Kate', 2, 40),
    ('Tom', 3, 80),
    ('Ali', 3, 20);

 select dts.Month, cts.Customer, isnull(t.Amount, 0) as Amount
      , sum(isnull(t.Amount, 0)) over(partition by cts.Customer order by dts.Month) as CumAmt 
  from ( select distinct customer 
                from @myTable
       ) cts 
  cross join ( select distinct Month 
                from @myTable 
             ) dts
  left join @myTable t
    on t.Customer = cts.Customer 
   and t.Month = dts.Month
 order by dts.Month, cts.Customer;

Month       Customer                                           Amount      CumAmt
----------- -------------------------------------------------- ----------- -----------
1           Ali                                                70          70
1           Kate                                               60          60
1           Tom                                                10          10
2           Ali                                                0           70
2           Kate                                               40          100
2           Tom                                                50          60
3           Ali                                                20          90
3           Kate                                               0           100
3           Tom                                                80          140

答案 7 :(得分:0)

尝试对分区进行求和 https://docs.microsoft.com/en-us/sql/t-sql/functions/sum-transact-sql

这将帮助您了解如何积累。如果我在postgresql中使用的代码是这样的 Select sum(amount) over(partition by customer, month)

答案 8 :(得分:0)

这应该为你做。此处还有指向聚合函数的Microsoft文档的链接。

https://docs.microsoft.com/en-us/sql/t-sql/functions/aggregate-functions-transact-sql

示例:

SELECT 
    Customer, Month, SUM(Amount) as Amount
FROM myTable
    GROUP BY Customer, Month
    ORDER BY Customer, Month