SQL Server group by date - sql

SELECT [DATE], [AMOUNT], SUM(AMOUNT) OVER (ORDER BY DATE) AS 'Running Total'
FROM PeopleActi
WHERE INSTANCE = 'Bank'
AND DATE IS NOT NULL
GROUP BY [DATE], [AMOUNT];
In the code above I selecting a user's date, amount and the "SUM(AMOUNT) OVER (ORDER BY DATE) AS 'Running Total'" is the running total of their costs over a period of dates. When I run this code I get the following results:
DATE AMOUNT Running Total
2018-10-05 100 100
2018-10-06 1000 1100
2018-10-07 5000 6100
2018-10-08 2000 8100
2018-10-09 1000 9100
2018-10-10 5000 14100
2018-10-11 3000 25100
2018-10-11 8000 25100
This works nicely but my issue is the last two rows. I wanted them to be grouped by their date and have the total amount for both same days, so it should be:
Date Amount Running Total
2018-10-11 11000 25100
Does anyone have an idea of how this can achieved? My [DATE] is of type DATE.
UPDATE!!!!
I've seen some of your solutions and they are good but its important I display the AMOUNT and the Running Total amount as well, so the final result should be...
DATE AMOUNT Running Total
2018-10-05 100 100
2018-10-06 1000 1100
2018-10-07 5000 6100
2018-10-08 2000 8100
2018-10-09 1000 9100
2018-10-10 5000 14100
2018-10-11 11000 25100
Thank you everyone for the help so far!

Group up the amounts and then do your cumulative total
WITH CTE
AS
(
SELECT A.Dt,
SUM(A.Amount) AS Amount
FROM (
VALUES ('2018-10-05',100),
('2018-10-06',1000),
('2018-10-07',5000),
('2018-10-08',2000),
('2018-10-09',1000),
('2018-10-10',5000),
('2018-10-11',3000),
('2018-10-11',8000)
) AS A(Dt,Amount)
GROUP BY A.Dt
)
SELECT C.Dt,
C.Amount,
SUM(C.Amount) OVER (ORDER BY C.Dt) AS CumTotal
FROM CTE AS C;

Try like below
SELECT [DATE],sum( [AMOUNT]), SUM(AMOUNT) OVER (ORDER BY DATE) AS 'Running Total'
FROM PeopleActi
WHERE INSTANCE = 'Bank'
AND DATE IS NOT NULL
GROUP BY [DATE]

If you need groping sum then why you are using window function, only aggregation is enough :
SELECT [DATE], SUM([AMOUNT])
FROM PeopleActi
WHERE INSTANCE = 'Bank' AND DATE IS NOT NULL
GROUP BY [DATE];

Try this
;WITH CTe([DATE],AMOUNT)
AS
(
SELECT '2018-10-05', 100 UNION ALL
SELECT '2018-10-06', 1000 UNION ALL
SELECT '2018-10-07', 5000 UNION ALL
SELECT '2018-10-08', 2000 UNION ALL
SELECT '2018-10-09', 1000 UNION ALL
SELECT '2018-10-10', 5000 UNION ALL
SELECT '2018-10-11', 3000 UNION ALL
SELECT '2018-10-11', 8000
)
SELECT DISTINCT [DATE],SUM(AMOUNT)OVER(PARTITION BY [DATE] ORDER BY [DATE]) AMOUNT , SUM(AMOUNT)OVER( ORDER BY [DATE]) AS RuningTot FROM CTe
Script
SELECT DISTINCT [DATE],
SUM(AMOUNT)OVER(PARTITION BY [DATE] ORDER BY [DATE]) AS AMOUNT,
SUM(AMOUNT) OVER (ORDER BY DATE) AS 'Running Total'
FROM PeopleActi
WHERE INSTANCE = 'Bank'
AND DATE IS NOT NULL

I would use a CTE to first group by Date, and then do your running total ..
So something like
with myAmounts AS
(
SELECT [DATE], SUM([AMOUNT]) AS Amount
FROM PeopleActi
WHERE INSTANCE = 'Bank'
AND DATE IS NOT NULL
GROUP BY [DATE]
)
SELECT [DATE], [AMOUNT], SUM(AMOUNT) OVER (ORDER BY DATE) AS 'Running Total'
FROM myAmounts
GROUP BY [DATE], [AMOUNT]
;
HTH,
B
ps; just saw that its the same answer as another .. democoding in action

Every field in a group by is going to cause it to potentially create new lines. If you SUM the amount field and remove it from your grouping, that should solve the issue. EDIT: I see the issue, I provided a fully stand alone example of the query below that you can adapt.
DECLARE #PeopleActi TABLE ([DATE] DATE,[AMOUNT] MONEY)
INSERT INTO #PeopleActi SELECT '2018-10-05',100
INSERT INTO #PeopleActi SELECT '2018-10-06',1000
INSERT INTO #PeopleActi SELECT '2018-10-07',5000
INSERT INTO #PeopleActi SELECT '2018-10-08',2000
INSERT INTO #PeopleActi SELECT '2018-10-09',1000
INSERT INTO #PeopleActi SELECT '2018-10-10',5000
INSERT INTO #PeopleActi SELECT '2018-10-11',3000
INSERT INTO #PeopleActi SELECT '2018-10-11',8000
SELECT *, SUM(AMOUNT) OVER (ORDER BY DATE) AS 'Running Total'
FROM (
SELECT [DATE], SUM([AMOUNT]) AS AMOUNT
FROM #PeopleActi
WHERE DATE IS NOT NULL
GROUP BY [DATE]
) a
GROUP BY [DATE],Amount

Try Subselect:
SELECT p.[DATE], p.[AMOUNT], SUM(AMOUNT) OVER (ORDER BY DATE) AS 'Running Total'
FROM
(
select [date], sum([amount]) as Amount from PeopleActi
WHERE INSTANCE = 'Bank'
AND DATE IS NOT NULL
group by [date]
) p
GROUP BY p.[DATE], p.[AMOUNT]

Related

T-SQL. GroupBy Truncated DATETIME and order by

I have a simple table of Orders like:
Order
=========
Date (DATETIME)
Price (INT)
And I would like to know how much money we earned per every month and output should look like:
January-2018 : 100
February-2018: 200
...
January-2019: 300
...
I have the following SQL:
SELECT
DATENAME(MONTH , DATEADD(M, t.MDate , -1 ) ) + '-' + CAST(t.YDate as NVARCHAR(20)),
SUM(Price)
FROM
(
SELECT
DATEPART(YYYY, o.Date) as YDate,
DATEPART(MM, o.Date) as MDate,
Price
FROM [Order] o
) t
GROUP BY t.YDate, t.MDate
ORDER BY t.YDate, t.MDate
Is it ok or may be there is a better approach ?
format() is the way to go. I would recommend:
select format(o.date, 'MMMM-yyyy') as Monthyear,
sum(o.price) as total
from orders o
group by format(datenew, 'MMMM-yyyy')
order by min(o.date)
If you are using Sql server 2012 or + , you can make use of format function as well.
select cast('2018-02-23 15:34:09.390' as datetime) as datenew, 100 as price into #temp union all
select cast('2018-02-24 15:34:09.390' as datetime) as datenew, 300 as price union all
select cast('2018-03-10 15:34:09.390' as datetime) as datenew, 500 as price union all
select cast('2018-03-11 15:34:09.390' as datetime) as datenew, 700 as price union all
select cast('2019-02-23 15:34:09.390' as datetime) as datenew, 900 as price union all
select cast('2019-02-23 15:34:09.390' as datetime) as datenew, 1500 as price
select Monthyear, total from (
select format(datenew, 'MMMM-yyyy') Monthyear, format(datenew, 'yyyyMM') NumMMYY ,sum(price) total from #temp
group by format(datenew, 'MMMM-yyyy') , format(datenew, 'yyyyMM') ) test
order by NumMMYY
Since format will convert it to nvarchar, I had to create one more column in the subquery to order it properly. If you don't mind one more column you don't have to use subquery, and you can order it with another column. I could not find any other way (except for case statement which is not a very good idea) to do it in the same select
Output:
Monthyear Total
February-2018 400
March-2018 1200
February-2019 2400
Maybe just with this?
with Orders as (
select convert(date,'2018-01-15') as [date], 10 as Price union all
select convert(date,'2018-01-20'), 20 union all
select convert(date,'2018-01-30'), 30 union all
select convert(date,'2018-02-15'), 20 union all
select convert(date,'2018-03-15'), 40 union all
select convert(date,'2018-03-20'), 50
)
select
datename(month,o.Date) + '-' + datename(year,o.Date) + ': ' +
convert(varchar(max),SUM(Price))
FROM [Orders] o
group by datename(month,o.Date) + '-' + datename(year,o.Date)
order by 1 desc
I don't get well why are you removing one month in your query, I am not doing it. You can test it here: https://rextester.com/GRKK80105

How to get the right order?

I have written queries to get the total qty of each month in 2016. Then I added another row called Total to sum up the total qty in 2016. But the ordermonth in the result turned out to be in a mess.
So, the question is is there any way to put the ordermonth in the right order? Both ASC and DESC are OK. Thanks in advance.
The query I've written:
WITH CTE AS(
SELECT CONVERT(CHAR(10), MONTH(orderdate)) AS ordermonth, SUM(qty) AS qty
FROM dbo.orders
WHERE YEAR(orderdate) = 2016
GROUP BY MONTH(orderdate)
)
SELECT * FROM CTE
UNION
SELECT 'Total', SUM(qty)
FROM dbo.orders
WHERE YEAR(orderdate) = 2016;
Current result:
ordermonth qty
1 4134
10 6454
11 9780
12 4000
2 5548
3 6970
4 3543
5 3309
6 4251
7 4997
8 6134
9 6926
Total 66046
First, you can do what you want without UNION. Something like this:
select coalesce(cast(month(orderdate) as varchar(255)), 'Total') as mon . . .
from . . .
group by grouping sets (month(orderdate), ())
order by month(orderdate)
No CTE, that's the entire query.
You can put into subquery and try like below:
select * from (
--your query including cte and union
) a
order by case when a.[Month] = 'Total' then 9999 else convert(int,a.[Month]) end
You can sort it by yyyymm, that is the best way even when you'll have more than one year, i.e.
order by orderyear * 100 + ordermonth
Or you can just add '0' for getting the right order like this:
order by right('0' + cast(ordermonth as varchar(2)), 2)
I found an easy way to solve this issue, that is, replacing UNION with UNION ALL.
WITH CTE AS(
SELECT CONVERT(CHAR(10), MONTH(orderdate)) AS ordermonth, SUM(qty) AS qty
FROM dbo.orders
WHERE YEAR(orderdate) = 2016
GROUP BY MONTH(orderdate)
)
SELECT * FROM CTE
UNION ALL
SELECT 'Total', SUM(qty)
FROM dbo.orders
WHERE YEAR(orderdate) = 2016;

Any one help me to solve this i try my best but did not solve this?

ItemName Price CreatedDateTime
New Card 50.00 2014-05-26 19:17:09.987
Recharge 110.00 2014-05-26 19:17:12.427
Promo 90.00 2014-05-27 16:17:12.427
Membership 70.00 2014-05-27 16:17:12.427
New Card 50.00 2014-05-26 19:20:09.987
Out Put : Need a query which Sum the sale of Current hour and
sale of item which have maximum sale in that hour in breakdownofSale
Column.
Hour SaleAmount BreakDownOfSale
19 210 Recharge
16 160 Promo
This should do it
create table #t
(
ItemName varchar(50),
Price decimal(18,2),
CreatedDateTime datetime
);
set dateformat ymd;
insert into #t values('New Card', 50.00, '2014-05-26 19:17:09.987');
insert into #t values('Recharge', 110.00, '2014-05-26 19:17:12.427');
insert into #t values('Promo', 90.00, '2014-05-27 16:17:12.427');
insert into #t values('Membership', 70.00, '2014-05-27 16:17:12.427');
insert into #t values('New Card', 50.00, '2014-05-26 19:20:09.987');
with cte as
(
select datepart(hh, CreatedDateTime) as [Hour],
ItemName,
Price,
sum(Price) over (partition by datepart(hh, CreatedDateTime)) SaleAmount,
ROW_NUMBER() over (partition by datepart(hh, CreatedDateTime) order by Price desc) rn
from #t
)
select Hour,
SaleAmount,
ItemName
from cte
where rn = 1
Though i am not clear with the question, based on your desired output, you may use the query as below.
SELECT DATEPART(HOUR,CreatedDateTime) AS Hour, sum(Price) AS Price, ItemName AS BreakDownOfSale from TableName WHERE BY ItemName,DATEPART(HOUR,CreatedDateTime)
Replace table name and column name with the actual one.
Hope this helps!
Here is the sample query.
You can use SQL Server Windows functions to get the result you need.
DECLARE #Table TABLE
(
ItemName NVARCHAR(40),
Price DECIMAL(10,2),
CreatedDatetime DATETIME
)
-- Fill table.
INSERT INTO #Table
( ItemName, Price, CreatedDatetime )
VALUES
( N'New Card' , 50.00 , '2014-05-26 19:17:09.987' ),
( N'Recharge' , 110.00 , '2014-05-26 19:17:12.427' ) ,
( N'Promo' , 90.00 , '2014-05-27 16:17:12.427' ) ,
( N'Membership' , 70.00 , '2014-05-27 16:17:12.427' ) ,
( N'New Card' , 50.00 , '2014-05-26 19:20:09.987' )
-- Check record(s).
SELECT * FROM #Table
-- Get record(s) in required way.
;WITH T1 AS
(
SELECT
DATEPART(HOUR, T.CreatedDatetime) AS Hour,
CONVERT(DATE, T.CreatedDatetime) AS Date,
T.ItemName AS BreakDownOfSales,
-- Date and hour both will give unique record(s)
SUM(Price) OVER (PARTITION BY CONVERT(DATE, T.CreatedDatetime), DATEPART(HOUR, CreatedDateTime)) AS SaleAmount,
ROW_NUMBER() OVER(PARTITION BY CONVERT(DATE, T.CreatedDatetime), DATEPART(HOUR, T.CreatedDatetime) ORDER BY T.Price DESC) AS RN
FROM
#Table T
)
SELECT
T1.Date ,
T1.Hour ,
T1.SaleAmount,
T1.BreakDownOfSales
FROM
T1
WHERE T1. RN = 1
ORDER BY
T1.Hour
Check this simple solution, Please convert it to SQL Server Query.
This will give you perfect result even if you have multiple date data.
SELECT HOUR(CreatedDateTime), SUM(Price),
(SELECT itemname FROM t it WHERE HOUR(ot.CreatedDateTime) = HOUR(it.CreatedDateTime) AND
DATE(ot.CreatedDateTime) = DATE(it.CreatedDateTime)
GROUP BY itemname
ORDER BY price DESC
LIMIT 1
) g
FROM t ot
GROUP BY HOUR(CreatedDateTime);

how to sum tow field at get inline result?

i have tow field for example credit an debit in one table.
and i need to sum them and get result at each line for example :
date debit credit amount
2015/01/01 20 0 20
2015/01/02 0 5 15
2015/01/03 0 30 -15
i hope you help me to get the amount by a query
thanks
With SQL-Server 2012 or newer you can use this:
SELECT [date], debit, credit, amount,
SUM(debit-credit) OVER(ORDER BY [date] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS amount
FROM TableName
ORDER BY [date]
Read: OVER-clause, especially the ROWS | RANGE part
With other versions you have to use a correlated subquery:
SELECT [date], debit, credit, amount,
(SELECT SUM(debit-credit)
FROM TableName t2
WHERE [date] <= t1.[date]) AS amount
FROM TableName t1
ORDER BY [date]
I agree with Tim's answer, I added some extra lines:
declare #credit as table (
[date] datetime,
amount int
)
declare #debit as table (
[date] datetime,
amount int
)
insert into #debit values
('2015-01-01', 20)
insert into #credit values
('2015-01-02', 5),
('2015-01-03', 30)
select
[date], debit, credit, SUM(debit-credit) OVER(ORDER BY [date] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS amount
from(
select
[date], sum(debit) debit, sum(credit) credit
from
(
select
[date], 0 credit, d.amount debit
from
#debit d
union all
select
[date], c.amount credit, 0 debit
from
#credit c
) j group by j.date
) x

multiple dates against count

I have 3 columns
Order_ID
Activation_Date
Order_Received_Date
So, if i distinctly count all the order_IDs on Order_Received_Date, I will get "Number of Orders" Similarly, if i distinctly count all the order_IDs on Activation_Date, I will get "Number of Activations"
What i want is two columns called "# Orders" and "# Activations"
Appreciate any inputs, thanks
I use union all for this type of calculation. The following is standard SQL so it should work in any database:
select thedate, sum(r) as numorders, sum(a) as numactivations
from (select activation_date as thedate, 1 as a, 0 as r from table t
union all
select order_received_date, 0, 1 from table t
) t
group by thedate
order by thedate;
If I understand you correctly, I guess the below query might help you solve this issue:
SELECT
OrderID,
ActivationDate,
OrderReceivedDate,
COUNT(OrderID) OVER (),
COUNT(ActivationDate) OVER ()
FROM
(
SELECT 1 AS OrderID, '2014-01-01' AS ActivationDate, '2013-12-15' AS OrderReceivedDate UNION
SELECT 2 AS OrderID, NULL AS ActivationDate, '2013-12-19' AS OrderReceivedDate UNION
SELECT 3 AS OrderID, '2014-03-01' AS ActivationDate, '2013-12-17' AS OrderReceivedDate UNION
SELECT 4 AS OrderID, '2014-04-01' AS ActivationDate, '2013-12-03' AS OrderReceivedDate
) t
I wish this helps you...