How to get count for each day between certain times - sql

I'm trying to get a total count for each day between 07:00 and 19:00 for the last 7 days. The below query only displays the count for the date 7 days back and not each individual day. Any help would be greatly appreciated. Thanks!
DECLARE #Date AS DATETIME = DATEADD(HOUR, 7, CAST(CAST(DATEADD(DAY, -7, GETDATE()) AS DATE) AS DATETIME))
DECLARE #Date2 AS DATETIME = DATEADD(HOUR, 19, CAST(CAST(DATEADD(DAY, -7, GETDATE()) AS DATE) AS DATETIME))
SELECT CONVERT(NVARCHAR(20), DATE, 120) AS Report_Date, COUNT(DISTINCT GUID) AS ROW_COUNT
FROM TABLE WITH (NOLOCK)
WHERE DATEADD(MINUTE, +270, DATE) >= #Date
AND DATEADD(MINUTE, +270, DATE) < #Date2
GROUP BY CONVERT(NVARCHAR(20), DATE, 120)

As you need past past 7days so use getdate()- 7
SELECT CAST(DATE as DATE) AS Report_Date,
COUNT(DISTINCT GUID) AS ROW_COUNT
FROM t
WHERE DATEPART(HOUR, DATE) >= 7 AND
DATEPART(HOUR, DATE) < 19
and CAST(DATE as DATE)>=getdate()-7 and CAST(DATE as DATE)<=getdate()
GROUP BY CAST(DATE as DATE)
ORDER BY CAST(DATE as DTE)

Don't convert date columns to dates. Use date functions. I don't understand why you are adding 270 minutes to the date.
I would go for a more direct answer to your question:
SELECT CAST(DATE as DATE) AS Report_Date,
COUNT(DISTINCT GUID) AS ROW_COUNT
FROM TABLE
WHERE DATEPART(HOUR, DATE) >= 7 AND
DATEPART(HOUR, DATE) < 19
GROUP BY CAST(DATE as DATE)
ORDER BY CAST(DATE as DTE)

;With T AS
(
SELECT CAST(DATE as DATE) AS Report_Date,COUNT(DISTINCT GUID) AS ROW_COUNT
FROM tbl
WHERE
DATEPART(HOUR, DATE) >= 7 AND DATEPART(HOUR, DATE) < 19
)
SELECT Report_date,Row_Count From T GROUP BY Report_date
ORDER BY Report_date

Related

SQL Server, filter for max date and max date minus 7 days

I'm trying to design a view and apply several conditions on my timestamp (datetime): last date and last date minus 7 days.
This works fine for the last date:
SELECT *
FROM table
WHERE timestamp = (SELECT MAX(timestamp) FROM table)
I couldn't figure out the way to add minus 7 days so far.
I tried, for instance
SELECT *
FROM table
WHERE (timestamp = (SELECT MAX(timestamp) FROM table)) OR (timestamp = (SELECT DATEADD(DAY, -7, MAX(timestamp)) FROM table)
and some other variations, including GETDATE() instead of MAX, however, I'm getting the execution timeout messages.
Please let me know what logic should I follow in this case.
Data looks like this, but there's more of it :)
So I want to get data only for rows with 29/11/2019 and 22/11/2019. I have an additional requirement for filtering for factors, but it's a simple one.
If you care about dates, then perhaps you want:
select t.*
from t cross join
(select max(timestamp) as max_timestamp from t) tt
where (t.timestamp >= convert(date, max_timestamp) and
t.timestamp < dateadd(day, 1, convert(date, max_timestamp))
) or
(t.timestamp >= dateadd(day, -7, convert(date, max_timestamp)) and
t.timestamp < dateadd(day, -6, convert(date, max_timestamp))
);
So I ended up with the next code:
SELECT *
FROM table
WHERE (timestamp >= CAST(DATEADD(DAY, - 1, GETDATE()) AS datetime)) AND (timestamp < CAST(GETDATE() AS DATETIME)) OR
(timestamp >= CAST(DATEADD(DAY, - 8, GETDATE()) AS datetime)) AND (timestamp < CAST(DATEADD(day, - 7, GETDATE()) AS DATETIME)) AND (Factor1 = 'Criteria1' OR
Factor2 = 'Criteria2')
Not sure if it's the best or the most elegant solution, but it works for me.

SQL Show 0 Values when no values between date range

i have some problems with my sql query.
Im selecting some values with a specific date range.
for example 2018-05-01 to 2018-05-13 this is the output.
SUM CalendarWeek
8 18
5 19
If the user will select now a date between 2018-04-01 and 2018-05-13 i want to show a 0 instead when there are no values.
For example:
SUM CalendarWeek
0 13
0 14
0 15
0 16
0 17
8 18
5 19
My Query:
SELECT SUM(Codes) AS 'Sum', CW FROM(
SELECT Count(*) AS 'Codes', DATEPART(wk, ScanDate) AS 'CW',
FROM [Table]
WHERE CONVERT(date, ScanDate, 102) >= '2018-01-01' AND CONVERT(date, ScanDate, 102) <= '2018-05-13'
GROUP BY ScanDate, DATEPART(wk, ScanDate)
UNION ALL
SELECT Count(*) AS 'Codes', DATEPART(wk, ScanDate) AS 'CW', ScanDate
FROM [Table_Archive]
WHERE CONVERT(date, ScanDate, 102) >= '2018-01-01' AND CONVERT(date, ScanDate, 102) <= '2018-05-13'
GROUP BY ScanDate, DATEPART(wk, ScanDate)) test
GROUP BY CW, ScanDate
ORDER BY CW ASC
any ideas how to solve this?
Thanks
First, you have to maintain calender table for such kind of task. If, so then use them. else would need to use recursive cte
declare #stardate date, #enddate date
set #stardate = '2018-04-01'
set #enddate = '2018-05-13'
with t as (
select DATEPART(ISO_WEEK, #stardate) as CalendarWeek
union all
select CalendarWeek+1
from t
where CalendarWeek < DATEPART(ISO_WEEK, #enddate)
)
select t1.sum, coalesce(t.CalendarWeek, 0) CalendarWeek
from t
left join table t1 on t1.CalendarWeek = t.CalendarWeek
SELECT ISNULL(SUM, 0), CalendarWeek
You can use IF in MySQL:
Select IF(sum=null, 0,sum) as sum from table_name
If you don't find solution now from this you can comment again I will give the exact query

select all from table using date with time

how can I get the last recorded data of the time 23:59 from yesterday and the day before?
my code doesn't have a filter of the time yet so it only shows all the data from yesterday and the day before.
select *
from tbl_Total
where date between DATEADD(day, -3, GETDATE()) AND DATEADD(day, -1, GETDATE())
In your case,
select * from tbl_Total as of timestamp timestamp '2017-07-19 23:59:59'
and
select * from tbl_Total as of timestamp timestamp '2017-07-18 23:59:59'
Try this
select *
from tbl_Total
where date between dateadd(day,-3,convert(varchar(10),getdate(),112)) AND dateadd(day,-3,convert(varchar(10),getdate(),112)+ ' 23:59:59:997' )
This query will return yestarday date with time 23:59:59.
SELECT CAST(CAST(CAST(DATEADD(day, -1, GETDATE()) as DATE) as varchar(12)) +' 23:59:59' as datetime2)
So you can use it in your query:
select *
from tbl_Total
where date between DATEADD(day, -3, GETDATE()) AND CAST(CAST(CAST(DATEADD(day, -1, GETDATE()) as DATE) as varchar(12)) +' 23:59:59' as datetime2)
EDIT: More elegant way:
SELECT DATEADD(second, -1, DATEADD(dd, DATEDIFF(dd,0,GETDATE()),0))
This query returns yesterday date with time 23:59:59.
EDIT2: If you want to return the day before with time 23:59:59 you need to use this query:
SELECT DATEADD(second, -1, DATEADD(dd, DATEDIFF(dd,1,GETDATE()),0))
If you want to obtain any other day you can change number 2 and test it.
Assuming you don't know the exact time you can get the latest rows using ROW_NUMBER:
with cte as
( select *,
row_number() -- for each day sorted descending
over (partition by DATEADD(dd, DATEDIFF(dd,0,GETDATE()),0)
order by date desc) as rn
from tbl_Total
where -- yesterday between 23:59 and 23:59:99.999
( date >= DATEADD(dd, DATEDIFF(dd,0,GETDATE()),0) - (1.0/1440)
and date < DATEADD(dd, DATEDIFF(dd,0,GETDATE()),0)
)
or -- day before yesterday between 23:59 and 23:59:99.999
( date >= DATEADD(dd, DATEDIFF(dd,1,GETDATE()),0) - (1.0/1440)
and date < DATEADD(dd, DATEDIFF(dd,1,GETDATE()),0)
)
)
select * from cte
where rn = 1 --latest row only

How to reduce the query execution time

SELECT dt AS Date
,monthname
,dayname
,(
SELECT COUNT(1)
FROM Calendar
WHERE DATEPART(MM, dt) = DATEPART(MM, c.dt)
AND DATEPART(YEAR, dt) = DATEPART(YEAR, c.dt)
) AS daysInMonth
FROM Calendar AS c
WHERE dt BETWEEN '2000-01-01 00:00:00'
AND '2020-02-01 00:00:00'
the above query is for getting number of days of particular month for a particular date. here iam giving date range and for all the dates between the range iam just showing the days of that month.
The image shows the results for the query and its taking 25secs for ~7500 rows. can someone help me to reduce the time.
Try this one. Here you calculate the total only once instead of 7500 times.
Also create the index for dt field
with monthCount as (
SELECT DATEPART(YEAR, dt) as m_year,
DATEPART(MM, dt) as m_month
COUNT(1) as total
FROM Calendar
GROUP BY
DATEPART(YEAR, dt),
DATEPART(MM, dt)
)
SELECT dt AS Date
,monthname
,dayname
,total
FROM Calendar C
JOIN monthCount M
on DATEPART(YEAR, C.dt) = M.m_year
and DATEPART(MM, C.dt) = M.m_month
WHERE C.dt BETWEEN '2000-01-01 00:00:00'
AND '2020-02-01 00:00:00'

Is there a better way to group a log on minutes?

I have the following that selects from a log and groups down to minute (excluding seconds and milisec):
SELECT DATEPART(YEAR, [Date]) AS YEAR, DATEPART(MONTH, [Date]) AS MONTH,
DATEPART(DAY, [Date]) AS DAY, DATEPART(HOUR, [Date]) AS HOUR,
DATEPART(MINUTE, [Date]) AS MIN, COUNT(*) AS COUNT
FROM [database].[dbo].[errorlog]
GROUP BY DATEPART(YEAR, [Date]), DATEPART(MONTH, [Date]), DATEPART(DAY, [Date]),
DATEPART(HOUR, [Date]), DATEPART(MINUTE, [Date])
ORDER BY DATEPART(YEAR, [Date]) DESC, DATEPART(MONTH, [Date]) DESC,
DATEPART(DAY, [Date]) DESC, DATEPART(HOUR, [Date]) DESC,
DATEPART(MINUTE, [Date]) DESC;
But as you can see thats a lot of fuzz just for getting a count, so I wonder if there is a better way to group it so I get grouped down to minutes in respect to year, month, day and hour?
This should would work:
select CAST([Date] AS smalldatetime) as time_stamp, count(*) as count
FROM [database].[dbo].[errorlog]
group by CAST([Date] AS smalldatetime)
order by CAST([Date] AS smalldatetime) desc;
Update after comments on this answer:
select dateadd(second,-datepart(ss,[Date]),[Date]) as time_stamp, count(*) as count
FROM [database].[dbo].[errorlog]
group by dateadd(second,-datepart(ss,[Date]),[Date])
order by dateadd(second,-datepart(ss,[Date]),[Date]) desc ;
The first solution rounds up the timestamp to the nearest minute. I realised that this is not exactly what the OP wanted.
So, the second solution just substracts the seconds part from the timestamp and leaves the timestamp with seconds as zero(Assuming [Date] does not have fractional seconds)
DATEADD(minute,DATEDIFF(minute,'20010101',[Date]),'20010101')
Should round all Date column values down to the nearest minute. So:
SELECT DATEADD(minute,DATEDIFF(minute,'20010101',[Date]),'20010101'),
COUNT(*) AS COUNT
FROM [database].[dbo].[errorlog]
GROUP BY DATEADD(minute,DATEDIFF(minute,'20010101',[Date]),'20010101')
ORDER BY DATEADD(minute,DATEDIFF(minute,'20010101',[Date]),'20010101') DESC;
(You could move this expression into a subquery if you want to further reduce the repetition)
You could do something like this to get
declare #now datetime
set #now = GETDATE()
select dateadd(minute, mm, #now) as date, c from (
select DATEDIFF(minute, #now, [Date]) as mm, COUNT(1) as c
from [database].[dbo].[errorlog]
group by DATEDIFF(minute, #now, [Date])
) t