Reputation: 8004
I have this table on 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
I want the select to get accumulation of the customer for each month
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
Noticing that Ali has no data for the month of 2 and Kate has no data for the month of 3
I have done it but the problem is that for the missing month for each customer no data shows i.e. Kate has to be in month 3 with 100 amount and Ali has to be in Month 2 with 70 amount
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
Upvotes: 8
Views: 622
Reputation: 45096
I think this does what you want
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
Upvotes: 1
Reputation:
to be clear(in answer Amount and 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
Upvotes: 1
Reputation: 1484
try this: 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
Upvotes: 1
Reputation: 585
Try this the table name is "a". Using a combination of Cte and sub query. Tried it out in 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
Upvotes: 1
Reputation: 2328
Do you want get the sum amount every month for each customer , what ever the customer has transaction in that month? In following script, If you have a customer table, you can join the customer table, do not need use (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
Upvotes: 1
Reputation: 1460
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
Upvotes: 2
Reputation: 50163
Use window function
select Customer, Month,
sum(Amount) over (partition by customer order by month) Amount
from table t
So, you want some kind of look up
tables which has possible months with customers.
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
Result :
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
Upvotes: 3
Reputation: 1169
This should do it for you. Also here is a link to the Microsoft docs regarding aggregation functions.
https://learn.microsoft.com/en-us/sql/t-sql/functions/aggregate-functions-transact-sql
Example:
SELECT
Customer, Month, SUM(Amount) as Amount
FROM myTable
GROUP BY Customer, Month
ORDER BY Customer, Month
Upvotes: 0
Reputation: 1549
Try Sum Over Partition By https://learn.microsoft.com/en-us/sql/t-sql/functions/sum-transact-sql
This will help you get the idea how to accumulate. If the code i use in postgresql like this
Select sum(amount) over(partition by customer, month)
Upvotes: 0