SQL query result needs to be summed - sql

Code is
select customerid, count(campaignid) as T, Convert (varchar, CreatedOn,23) from customerbenefits
where campaignid='6EDBB808-1A91-4B1D-BE1D-27EF15C5D4C7'
and createdon between '2019-09-01' and '2019-10-01'
group by customerid,CreatedOn
having count(campaignid)>1
order by createdon desc
Result is
-- id / count /time
--18655680-3B5E-4001-1984-00000000 / 12 /2019-09-30
--18655680-3B5E-4001-1984-00000000 / 7 / 2019-09-30
--18655680-3B5E-4001-1984-00000000 / 6 / 2019-09-30
I want result as
-- id / count / time
-- 18655680-3B5E-4001-1984-00000000 / 25/ 2019-09-30
I want it grouped to time filter and sum counts.
How can I change my query?

Use two levels of aggregation:
select customerid, dte, sum(T)
from (select customerid, count(*) as T, convert(varchar(255), CreatedOn, 23) as dte
from customerbenefits
where campaignid = '6EDBB808-1A91-4B1D-BE1D-27EF15C5D4C7' and
createdon >= '2019-09-01' and
createdon < '2019-10-01'
group by customerid, CreatedOn
having count(*) > 1
) t
group by customerid, dte
order by createdon desc ;
Notice that I changed the date comparisons so midnight on 2019-10-01 is not included in the data for September.

Related

How to replace the loop in MsSQL?

For example
If I want to check in every day last week
select count(ID) from DB where date < "2019/07/01"
select count(ID) from DB where date < "2019/07/02"
select count(ID) from DB where date < "2019/07/03"
...
select count(ID) from DB where date < "2019/07/08"
like
0701 10
0702 15
0703 23
...
0707 45
How to do this without loop and one query?
You can generate the dates using a recursive CTE (or other method) and then run the query:
with dates as (
select convert(date, '2019-07-01') as dte union all
select dateadd(day, 1, dte)
from dates
where dte < '2019-07-08'
)
select d.dte,
(select count(*) from DB where DB.date < d.dte)
from dates d;
More efficient, though, is a cumulative sum:
select db.*
from (select date, count(*) as cnt, sum(count(*)) over (order by date) as running_cnt
from db
group by date
) d
where d.date >= '2019-07-01' and d.date < '2019-07-09';
Are you just counting the number by day?
Something like
SELECT MONTH(date), DAY(date), COUNT(ID)
FROM DB
GROUP BY MONTH(date), DAY(date);
(assuming date is a DATE or DATETIME)
Do it with window Count. range between current row and current row selects exactly this day rows.
select distinct date, count(1) over (order by Date) - count(1) over (order by Date range between current row and current row)
from DB
where date between '2019-07-01' and '2019-07-08';
I assume date column is exactly DATE.

Get last data recorded of the date and group it by month

tbl_totalMonth has id,time, date and kwh column.
I want to get the last recorded data of the months and group it per month so the result would be the name of the month and kwh.
the result should be something like this:
month | kwh
------------
January | 150
February | 400
the query I tried: (but it returns the max kwh not the last kwh recorded)
SELECT DATENAME(MONTH, a.date) as monthly, max(a.kwh) as kwh
from tbl_totalMonth a
WHERE date > = DATEADD(yy,DATEDIFF(yy,0, GETDATE() -1 ),0)
group by DATENAME(MONTH, a.date)
I suspect you need something quite different:
select *
from (
select *
, row_number() over(partition by month(a.date), year(a.date) order by a.date DESC) as rn
from tbl_totalMonth a
WHERE date > = DATEADD(yy,DATEDIFF(yy,0, GETDATE() -1 ),0)
) d
where rn = 1
To get "the last kwh recorded (per month)" you need to use row_number() which - per month - will order the rows (descending) and give each one a row number. When that number is 1 you have "the most recent" row for that month, and you won't need group by at all.
You could use group by and month
select datename(month, date), sum(kwh)
from tbl_totalMonth
where date = (select max(date) from tbl_totalMonth )
group by datename(month, date)
if you need only the last row for each month then youn should use
select datename(month, date), khw
from tbl_totalMonth a
inner join (
select max(date) as max_date
from tbl_totalMonth
group by month(date)) t on t.max_date = a.date

Returning only one row for an aggregate function per a time period and user

I'm using SQL Server 2008.
I have table constructed the following way:
Date (datetime)
TimeIn (datetime)
TimeOut (datetime)
UserReference (nvarchar)
LocationID
My desired results are: For every hour between hour 7 (7am) and hour 18 (6pm) I want to know the user who had the highest (TimeIn - TimeOut) for every location. -last condition is optional-
So I've got an aggregated function which calculates the datediff in seconds between TimeOut and TimeIn aliased as Total
I want my results to look a bit like this:
Hour 7 | K1345 | 50 | Place #5
Hour 7 | K3456 | 10 | Place #4
Hour 8 | K3333 | 5 | Place #5
etc.
What I've tried so far:
A CTE using the ROW_NUMBER() function, partitioning by my aggregated column and ordering by it. This only returns one row.
A CTE where I do all my aggregations (including datepart(hour,date)) and use the max aggregation to get the highest total time in my outer query.
I know I have to do it with a CTE somehow, I'm just not exactly sure how to join the cte and my outer query.
Am I on the right track using a ROW_NUMBER() or Rank()?
Queries I've tried:
WITH cte as
(
SELECT * ,
rn = ROW_NUMBER() over (partition by datediff(second, [TimeIn], [TimeOut])order by datediff(second, [TimeIn], [TimeOut]) desc)
FROM TimeTable (nolock)
where DateCreated > '20131023 00:00:00' and DateCreated < '20131023 23:59:00'
)
SELECT datepart(hour,cte.DateCreated) as hour,cte.UserReference,(datediff(second, [TimeIn], [TimeOut])) as [Response Time],LocationID
from cte
where cte.rn = 1
and DATEPART(hh,datecreated) >= 7 and DATEPART(hh,datecreated) <= 18
order by hour asc
This only returns a few rows
something else I've tried:
with cte as
(
SELECT Datecreated as Date,
UserReference as [User],
datediff(second, [TimeIn], [TimeOut]) as Time,
LocationID as Location
FROM TimeTable
WHERE datecreated... --daterange
)
SELECT DATEPART(HOUR,date), cte.[User], MAX(Time), Location
FROM cte
WHERE DATEPART(hh,datecreated) >= 7 and DATEPART(hh,datecreated) <= 18
GROUP BY DATEPART(HOUR,date), cte.[User], Location
Row of sample data
Date UserRef TimeIn TimeOut locationid
2013-10-23 06:26:12.783 KF34334 2013-10-23 06:27:07.000 2013-10-23 06:27:08.000 10329
I hope this will help
WITH TotalTime AS (
SELECT
CAST(DateCreated AS DATE) as [date]
,DATEPART(hour,DateCreated) AS [hour]
,SUM(DATEDIFF(second,TimeIn,TimeOut)) AS Total
,UserReference
,locationid
FROM TimeTable
GROUP BY UserReference,locationid,CAST(DateCreated AS DATE),DATEPART(hour,DateCreated)
HAVING DATEPART(hh,DateCreated) >= 7 and DATEPART(hh,DateCreated) <= 18
)
, rn AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY [date],[hour],locationid ORDER BY Total DESC) AS row_num
FROM TotalTime
)
SELECT *
FROM rn
WHERE row_num = 1

sql to find row for min date in each month

I have a table, lets say "Records" with structure:
id date
-- ----
1 2012-08-30
2 2012-08-29
3 2012-07-25
I need to write an SQL query in PostgreSQL to get record_id for MIN date in each month.
month record_id
----- ---------
8 2
7 3
as we see 2012-08-29 < 2012-08-30 and it is 8 month, so we should show record_id = 2
I tried something like this,
SELECT
EXTRACT(MONTH FROM date) as month,
record_id,
MIN(date)
FROM Records
GROUP BY 1,2
but it shows 3 records.
Can anybody help?
SELECT DISTINCT ON (EXTRACT(MONTH FROM date))
id,
date
FROM Records1
ORDER BY EXTRACT(MONTH FROM date),date
SQLFiddle http://sqlfiddle.com/#!12/76ca2/3
UPD: This query:
1) Orders the records by month and date
2) For every month picks the first record (the first record has MIN(date) because of ordering)
Details here http://www.postgresql.org/docs/current/static/sql-select.html#SQL-DISTINCT
This will return multiples if you have duplicate minimum dates:
Select
minbymonth.Month,
r.record_id
From (
Select
Extract(Month From date) As Month,
Min(date) As Date
From
records
Group By
Extract(Month From date)
) minbymonth
Inner Join
records r
On minbymonth.date = r.date
Order By
1;
Or if you have CTEs
With MinByMonth As (
Select
Extract(Month From date) As Month,
Min(date) As Date
From
records
Group By
Extract(Month From date)
)
Select
m.Month,
r.record_id
From
MinByMonth m
Inner Join
Records r
On m.date = r.date
Order By
1;
http://sqlfiddle.com/#!1/2a054/3
select extract(month from date)
, record_id
, date
from
(
select
record_id
, date
, rank() over (partition by extract(month from date) order by date asc) r
from records
) x
where r=1
order by date
SQL Fiddle
select distinct on (date_trunc('month', date))
date_trunc('month', date) as month,
id,
date
from records
order by 1, 3 desc
I think you need use sub-query, something like this:
SELECT
EXTRACT(MONTH FROM r.date) as month,
r.record_id
FROM Records as r
INNER JOIN (
SELECT
EXTRACT(MONTH FROM date) as month,
MIN(date) as mindate
FROM Records
GROUP BY EXTRACT(MONTH FROM date)
) as sub on EXTRACT(MONTH FROM r.date) = sub.month and r.date = sub.mindate

How to count number of records per day?

I have a table in a with the following structure:
CustID --- DateAdded ---
396 2012-02-09
396 2012-02-09
396 2012-02-08
396 2012-02-07
396 2012-02-07
396 2012-02-07
396 2012-02-06
396 2012-02-06
I would like to know how I can count the number of records per day, for the last 7 days in SQL and then return this as an integer.
At present I have the following SQL query written:
SELECT *
FROM Responses
WHERE DateAdded >= dateadd(day, datediff(day, 0, GetDate()) - 7, 0)
RETURN
However this only returns all entries for the past 7 days. How can I count the records per day for the last 7 days?
select DateAdded, count(CustID)
from Responses
WHERE DateAdded >=dateadd(day,datediff(day,0,GetDate())- 7,0)
GROUP BY DateAdded
select DateAdded, count(CustID)
from tbl
group by DateAdded
about 7-days interval it's DB-depending question
SELECT DateAdded, COUNT(1) AS NUMBERADDBYDAY
FROM Responses
WHERE DateAdded >= dateadd(day,datediff(day,0,GetDate())- 7,0)
GROUP BY DateAdded
This one is like the answer above which uses the MySql DATE_FORMAT() function. I also selected just one specific week in Jan.
SELECT
DatePart(day, DateAdded) AS date,
COUNT(entryhash) AS count
FROM Responses
where DateAdded > '2020-01-25' and DateAdded < '2020-02-01'
GROUP BY
DatePart(day, DateAdded )
If your timestamp includes time, not only date, use:
SELECT DATE_FORMAT('timestamp', '%Y-%m-%d') AS date, COUNT(id) AS count FROM table GROUP BY DATE_FORMAT('timestamp', '%Y-%m-%d')
You could also try this:
SELECT DISTINCT (DATE(dateadded)) AS unique_date, COUNT(*) AS amount
FROM table
GROUP BY unique_date
ORDER BY unique_date ASC
SELECT count(*), dateadded FROM Responses
WHERE DateAdded >=dateadd(day,datediff(day,0,GetDate())- 7,0)
group by dateadded
RETURN
This will give you a count of records for each dateadded value. Don't make the mistake of adding more columns to the select, expecting to get just one count per day. The group by clause will give you a row for every unique instance of the columns listed.
select DateAdded, count(DateAdded) as num_records
from your_table
WHERE DateAdded >=dateadd(day,datediff(day,0,GetDate())- 7,0)
group by DateAdded
order by DateAdded
Unfortunately the best answer here IMO is a comment by #Profex on an incorrect answer , but the solution I went with is
SELECT FORMAT(DateAdded, 'yyyy-MM-dd'), count(CustID)
FROM Responses
WHERE DateAdded >= dateadd(day,datediff(day,0,GetDate())- 7,0)
GROUP BY FORMAT(DateAdded, 'yyyy-MM-dd')
ORDER BY FORMAT(DateAdded, 'yyyy-MM-dd')
Note that I haven't tested this SQL since I don't have the OP's DB , but this approach works well in my scenario where the date is stored to the second
The important part here is using the FORMAT(DateAdded, 'yyyy-MM-dd') method to drop the time without losing the year and month , as would happen if you used DATEPART(day, DateAdded)
When a day among last 7 days, has no record means, the following code will list out that day with count as zero.
DECLARE #startDate DATE = GETDATE() - 6,
#endDate DATE = GETDATE();
DECLARE #daysTable TABLE
(
OrderDate date
)
DECLARE #daysOrderTable TABLE
(
OrderDate date,
OrderCount int
)
Insert into #daysTable
SELECT TOP (DATEDIFF(DAY, #startDate, #endDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #startDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
Insert into #daysOrderTable
select OrderDate, ISNULL((SELECT COUNT(*) AS OdrCount
FROM [dbo].[MyOrderTable] odr
WHERE CAST(odr.[CreatedDate] as date) = dt.OrderDate
group by CAST(odr.[CreatedDate] as date)
), 0) AS OrderCount from #daysTable dt
select * from #daysOrderTable
RESULT
OrderDate     OrderCount
2022-11-22     42
2022-11-23     6
2022-11-24     34
2022-11-25     0
2022-11-26     28
2022-11-27     0
2022-11-28     22
SELECT DATE_FORMAT(DateAdded, '%Y-%m-%d'),
COUNT(CustID)
FROM Responses
GROUP BY DATE_FORMAT(DateAdded, '%Y-%m-%d');