Currently I'm trying to grab the average date difference between the start and end datetime of multiple events which occur multiple times within the same month. There are four different types of Event which run for different amounts of time.
select
min(datetime) starttime,
max(datetime) endtime,
avg(endtime - min(datetime)) As avg_days,
event
from log_economy_event_point_spending a
AND datetime between '2021-01-01' AND '2021-04-30'
group by event
order by event
However, using this method, if the event occurs multiple times it takes the start of the first event, and the end of the last event. How do I write SQL code that can get the average datetime duration of different type of event?
Many thanks
Hmmm . . . I think you want:
select event,
min(datetime) as starttime, max(datetime) as endtime,
(max(datetime) - min(datetime)) / nullif(count(*) - 1, 0) As avg_days
from log_economy_event_point_spending leeps
where datetime >= '2021-01-01' and
datetime < '2021-05-01'
group by event
order by event;
This fixes the date/time arithmetic to get the average. Note the other changes:
The date comparison includes all date/time values in April, which I'm guessing is your intention. Your version eliminates values on April 30th.
The table aliases is meaningful rather than being an arbitrary letter.
You cannot re-use column aliases in the expressions in the select where the aliases are defined.
Related
I have a SQL query that includes a __DATE__ macro. A Python script replaces this macro with the current date and then the statement is executed thus giving one day's worth of data.
For the first item selected, I would like to use tblLabTestResult.CollectionDate instead of __DATE__.
I would like to include the prior 7 days instead of just the current day.
The desired output would be something similar to:
Date,Result,Total
2021-08-28,Detected,5
2021-08-28,Not Detected,9
2021-08-29,Detected,23
2021-08-29,Not Detected,6
2021-08-30,Detected,88
2021-08-30,Not Detected,26
Current query:
SELECT
'__DATE__' as Date,
tblLabTestResult.Result as Result,
Count(tblLabTestResult.Result) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
tblLabTestResult.TestName like '%cov%'
AND tblLabTestResult.TestName not like '%aoe%'
AND tblLabTestResult.TestName not like '%antibody%'
AND tblLabTestResult.CollectionDate >= '__DATE__'
AND tblLabTestResult.CollectionDate <= '__DATE__ 11:59:59 PM'
GROUP BY
tblLabTestResult.Result;
How can I change my SQL query to accommodate these requirements? I am using MS SQL Server.
You can use DATEADD() function to get the date from 7 days ago and use all dates between date-7days and date. I have updated where condition in your query below:
SELECT
'__DATE__' as Date,
tblLabTestResult.Result as Result,
Count(tblLabTestResult.Result) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
tblLabTestResult.TestName like '%cov%'
AND tblLabTestResult.TestName not like '%aoe%'
AND tblLabTestResult.TestName not like '%antibody%'
AND tblLabTestResult.CollectionDate between DATEADD(day, -7, '__DATE__') and '__DATE__ 11:59:59 PM'
GROUP BY
tblLabTestResult.Result;
A few points:
Columns that are not aggregated must be in the GROUP BY
You should be passing your date as a parameter
Best to use a half-open interval to compare dates (exclusive end-point), so #endDate is the day after the one you want
Use short, meaningful aliases to make your code more readable
It doesn't make sense to group and aggregate by the same column. If Result is a non-nullable column then Count(Result) is the same as Count(*)
If you want to group by whole days (and CollectionDate has a time component) then replace ltr.CollectionDate with CAST(ltr.CollectionDate AS date) in both the SELECT and GROUP BY
SELECT
ltr.CollectionDate as Date,
ltr.Result as Result,
COUNT(*) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
ltr.TestName like '%cov%'
AND ltr.TestName not like '%aoe%'
AND ltr.TestName not like '%antibody%'
AND ltr.CollectionDate >= #startdate
AND ltr.CollectionDate < #endDate
GROUP BY
ltr.CollectionDate, ltr.Result;
I want to get a list of orders that are placed in a given date range, but exclude the orders placed between 2pm-10pm.
Can anyone help me to complete the below query
select *
from abc
where
date(order_created) between '2021-05-22' and '2021-05-24'
and not between <order placed between 2pm-10pm>
You can use time() to get the time part. That allows:
date(order_created) between '2021-05-22' and '2021-05-24' and
time(order_created) not between '14:00:00' and '20:00:00'
Note that this excludes both the end points. More commonly, you would want to exclude the first but keep the second:
date(order_created) between '2021-05-22' and '2021-05-24' and
(time(order_created) < '14:00:00' or
time(order_created) >= '20:00:00'
)
Try:
and EXTRACT(TIME FROM order_created) not between '14:00:00' and '22:00:00'
Note: I'm assuming your order_created column contains the time as well. FYI: in BigQuery there are two types of fields that contain date and time: Timestamp, and Datetime, so your order_created field is likely one of those two types. The SQL differs slightly between manipulating one type or the other, but the EXTRACT function works on both.
I am running the following query
select DateTime
from Calls
where DateTime > '17 Oct 2018 00:00:00.000' and
DialedNumberID = '1234'
What would this give me is a list of all the times that this number was dialled on the specific date.
Essentially what I am looking for is a query that would give me the average calls that take place every X minutes and would like to run the query for the whole year.
Thanks
I guess you have a table named Calls with the columns DateTime and DialedNumberID.
You can summarize the information in that table year-by-year using the kind of pattern.
SELECT YEAR(`DateTime`),
DialedNumberID,
COUNT(*) call_count
FROM Calls
GROUP BY YEAR(`DateTime`), DialedNumberID
The trick in this pattern is to GROUP BY f(date) . The function f() reduces any date to the year in which it occures.
Summary by five minute intervals, you need f(date) that reduces datestamps to five minute intervals. That function is a good deal more complex than YEAR().
DATE_FORMAT(datestamp,'%Y-%m-%d %H:00') + INTERVAL (MINUTE(datestamp) - MINUTE(datestamp) MOD 5)
Given, for example, 2001-09-11 08:43:00, this gives back 2001-09-11 08:40:00.
So, here's your summary by five minute intervals.
SELECT DATE_FORMAT(`DateTime`,'%Y-%m-%d %H:00')+INTERVAL(MINUTE(`DateTime`)-MINUTE(datestamp) MOD 5) interval_beginning,
DialedNumberID,
COUNT(*) call_count
FROM Calls
GROUP BY DATE_FORMAT(`DateTime`,'%Y-%m-%d %H:00')+INTERVAL(MINUTE(`DateTime`)-MINUTE(datestamp) MOD 5),
DialedNumberID
You can make this query clearer and less repetitive by defining a stored function for that ugly DATE_FORMAT() expression. But that's a topic for another day.
Finally, append
WHERE YEAR(`DateTime`) = YEAR(NOW())
AND DialedNumberID = '1234'
to the query to filter by the current year and a particular id.
This query will need work to make it as efficient as possible. That too is a topic for another day.
Pro tip: DATETIME is a reserved word in MySQL. Column names are generally case-insensitive. Avoid naming your columns, in this case DateTime, the same as a reserved word.
The average amount of calls per interval is the number of calls (COUNT(*)) divided by the minutes between the start and end of of the monitored period (TIMESTAMPDIFF(minute, period_start, period_end)) multiplied with the number of minutes in the desired interval (five in your example).
For MySQL:
select count(*) / timestampdiff(minute, date '2018-01-01', now()) * 5 as avg_calls
from calls
where `datetime` >= date '2018-01-01'
and dialednumberid = 1234;
For SQL Server:
select count(*) * 1.0 / datediff(minute, '20180101', getdate()) * 5 as avg_calls
from calls
where [datetime] >= '20180101'
and dialednumberid = 1234;
This forces the call time into 5 minute intervals. Use 'count' and 'group by' on these intervals. Using DateTime as a column name is confusing
SELECT DATEADD(MINUTE, CAST(DATEPART(MINUTE, [DateTime] AS INTEGER)%5 * - 1,CAST(FORMAT([DateTime], 'MM/dd/yyyy hh:mm') AS DATETIME)) AS CallInterval, COUNT(*)
FROM Calls
GROUP BY DATEADD(MINUTE, CAST(DATEPART(MINUTE, [DateTime]) AS INTEGER)%5 * - 1,CAST(FORMAT([DateTime], 'MM/dd/yyyy hh:mm') AS DATETIME))
Can anyone help me create a query which will populate a list of DJs who are not already booked in.
My user will select a start date (and time), and an end date (and time) - and then click a button to select a DJ.
I only want those DJs which are available between those time slots to appear in the list.
Here are the two tables which are involved
all I need in the listbox is the DJ Number, and the DJ Name
So far I have this... but it isn't working:
SELECT tblDJ.DJ_No AS [DJ ID], tblDJ.DJ_Name AS Name FROM tblDJ
WHERE (((tblDJ.[DJ_No]) Not In
(SELECT tblBooking.[FK_DJ_No]
FROM tblBooking
WHERE ( (tblBooking.End_Date) >= 01-04-2020 19:30:00 )))) ....etc....
I'm just entering a date in here for now, but obviously it will be stored in a variable once implemented.
Thanks
Implementing OVERLAPS of two intervals would look like:
1st_start_date <= 2nd_end_date and 1st_end_date >= 2nd_start_date
where 1st and 2nd values are markers of different events.
You could use that logic in combination with NOT EXISTS to discard those djs that are unavailable at a given time:
select dj_no, dj_name
from tbldj d
where not exists (
select 1
from tblbooking b
where b.fk_dj_no = d.dj_no
and b.start_date <= #END DATE#
and b.end_date >= #START DATE#
)
You just need to replace #START DATE# and #END DATE# with your values.
This does work because there are following assumptions:
Start date of the first event is prior to end date of that event
Start date of the second event is prior to end date of that event
Which seems logical, right?
The date in the SQL needs to be wrapped between two # in order for MS-Access to recognize it as a date:
select *
from tblDJ
where DJ_No not in
(
select FK_DJ_No
from tblBooking
where End_Date >= #2020-04-01 19:30:00#
)
Other than that you query will work.
I'm trying to find a way to display the last event held (last date and time) in an events table whilst displaying all the columns for that event without using ORDER BY.
For example:
SELECT * from Events
where dateheld in (select max(dateheld) from events)
AND starttime in (select max(starttime) from events)
When I put MAX starttime, it displays nothing. When I put MIN starttime it works but displays the earliest time of that date and not the latest.
I guess you could print out your records, throw them down the stairs, and the ones that go farthest have the "lightest" dates. You cannot sort without order by. It's like wanting water that isn't wet. Unless your data naturally comes out in the order you want, you MUST sort.
Of course, if you want only the record that has the absolute most recent date, and don't need more than just that one record, then
SELECT yourdatetimefield, ...
FROM yourtable
HAVING yourdatetimefield = MAX(yourdatetimefield)
If you are only looking for the latest item:
EDIT gets a little more complicated when you have seperate date and time fields, but this should work. This is a ridiculous kludge for a situation where date and time should be stored in one field.
SELECT *
FROM (
SELECT *
FROM Events
WHERE dateTime = (SELECT MAX(dateheld) FROM Events)
) temp
WHERE starttime = (SELECT MAX(starttime) FROM (
SELECT *
FROM Events
WHERE dateTime = (SELECT MAX(dateheld) FROM Events)
) temp 2 )