Reputation: 912
My table "DATA123" is as follows
NoticeDate------Amount
2016-02-14------60000
2015-11-06------10000
2015-12-02------10000
2016-01-13------50000
2016-01-24------10000
2015-12-29------30000
2016-01-12------20000
2015-11-18------50000
I want the output to be as
Year----month----Amount----Cumulative
2015----NOV------60000------60000
2015----DEC------40000------100000
2016----JAN------80000------180000
2016----FEB------60000------240000
In short i want orderly monthly report sql query (not procedure) with cumulative sum. However, I dont have a unique id representing each record.
Upvotes: 1
Views: 3051
Reputation: 3087
Using WITH
keyword, execute following query:
WITH cte AS
(
SELECT YEAR(NoticeDate) AS [Year],
Month(NoticeDate) AS [Month],
Amount
FROM DATA123
),
kte AS
(
SELECT ROW_NUMBER() OVER (ORDER BY [Year], [Month]) as RowNumber,
[Year],
[Month],
SUM(Amount) AS Amount
FROM cte
GROUP BY [Year], [Month]
)
SELECT (SELECT [Year] FROM kte WHERE RowNumber = t1.RowNumber) AS [Year],
(SELECT UPPER(CONVERT(CHAR(3), CAST('2000-' + CAST((SELECT [Month] FROM kte WHERE RowNumber = t1.RowNumber) AS NVARCHAR(2)) + '-01' AS DATE), 0))) AS [Month],
t1.Amount,
SUM(t2.Amount) AS Cumulative
FROM kte t1
JOIN kte t2 ON t1.RowNumber >= t2.RowNumber
GROUP By t1.RowNumber, t1.Amount
ORDER BY t1.RowNumber
By executing above query, following result should be got:
+-------------------------------------+
| Year | Month | Amount | Cumulative |
|------+-------+---------+------------+
| 2015 | NOV | 60000 | 60000 |
| 2015 | DEC | 40000 | 100000 |
| 2016 | JAN | 80000 | 180000 |
| 2016 | FEB | 60000 | 240000 |
+-------------------------------------+
Upvotes: 0
Reputation: 350242
I would suggest this query:
select datepart(year, NoticeDate1) Year,
format(NoticeDate1,'MMM') Month,
Amount,
sum(Amount) over (order by NoticeDate1
rows unbounded preceding) Cumulative
from (
select dateadd(month, datediff(month, 0, NoticeDate), 0) NoticeDate1,
sum(amount) Amount
from data123
group by dateadd(month, datediff(month, 0, NoticeDate), 0)
) a
It produces this output for the sample data:
| Year | Month | Amount | cumulative |
|------|-------|--------|------------|
| 2015 | Nov | 60000 | 60000 |
| 2015 | Dec | 40000 | 100000 |
| 2016 | Jan | 80000 | 180000 |
| 2016 | Feb | 60000 | 240000 |
The query makes use of windows functions with rows unbounding preceding
, which is the key for cumulative sums. NoticeData1
is the first day of the month for date NoticeDate
. The format
function can be used to get month names.
You might want to add an order by
clause, but then you better select the month number, because month names don't sort like you would want :). Still the sort order will be OK like it is now. The engine needs the correct sort order for the cumulative sum, so it has no reason to change it.
Upvotes: 2
Reputation: 62841
Since you're using 2012, here's one option using window functions
:
select
yr,
mth,
sumamount,
sum(sumamount) over (order by yr, mth rows unbounded preceding) runningsum
from (select year(noticedate) yr,
month(noticedate) mth,
sum(amount) sumamount
from data123
group by year(noticedate), month(noticedate)
) t
order by yr, mth
Upvotes: 2
Reputation: 1
You can use the DATEPART or DATENAME function, and also generate the row number with the ROW_NUMBER:
SELECT A.DataRowNumber, A.[year], A.[month], A.[day], A.[Ammount], SUM(B.[Ammount]) FROM (SELECT ROW_NUMBER() OVER (ORDER BY [NoticeDate]) AS 'DataRowNumber', DATEPART(YEAR, [NoticeDate]) AS 'year',DATENAME(MONTH, [NoticeDate]) AS 'month', DATEPART(DAY, [NoticeDate]) AS 'day',[Ammount]
FROM [dbo].[DATA123]) A INNER JOIN (SELECT ROW_NUMBER() OVER (ORDER BY [NoticeDate]) AS 'DataRowNumber', DATEPART(YEAR, [NoticeDate]) AS 'year',DATENAME(MONTH, [NoticeDate]) AS 'month', DATEPART(DAY, [NoticeDate]) AS 'day',[Ammount]
FROM [dbo].[DATA123]) B
ON A.[DataRowNumber] >= B.[DataRowNumber]
GROUP BY A.[DataRowNumber], A.[year], A.[month], A.[day], A.[peso_factura]
Upvotes: 0