The query below retrieves weather data from a MySql database, and groups this data in to an hourly format.
select hour(datetime) AS hour
, avg(Temperature) as AVGT
from Database.minute
WHERE DATETIME
BETWEEN (CURDATE() + INTERVAL (SELECT hour(NOW())) hour - INTERVAL 23 hour)
AND ((CURDATE() + INTERVAL (SELECT hour(NOW())) hour))
group by hour
order by (CURDATE() + INTERVAL (SELECT hour(NOW())) hour - INTERVAL 23 hour)
Output is as follows:
hour AVGT
19 11.730
20 11.970
21 11.970
22 11.760
23 11.660
0 11.700
1 11.830
2 12.370
3 12.770
4 12.840
5 12.840
6 12.540
7 12.500
8 12.030
9 12.100
10 12.300
11 12.060
12 11.090
13 10.920
14 10.920
15 10.820
16 10.760
17 10.690
18 10.560
The time is now 18:15. All of the above output is correct apart from the data gathered for hour '18'. Instead of getting the average value between 18:00 and 18:15, it just outputs the average at time 18:00. ie. ignoring data between 18:01 and 18:14.
How can I modify the above query to include data in the current hour (18:00 to Now)?
Thanks
Why don't you simply try
SELECT Hour(datetime) AS hour,
Avg(temperature) AS AVGT
FROM DATABASE.minute
WHERE datetime BETWEEN ( Curdate() + INTERVAL (SELECT Hour(Now())) hour -
INTERVAL 23 hour ) AND Now()
GROUP BY hour
ORDER BY ( Curdate() + INTERVAL (SELECT Hour(Now())) hour - INTERVAL 23 hour )
I agree with #Ankur's answer (your filter citerion should not filter records up to the current hour, but rather the current time), however your date/time operations are very strange:
You don't need a subquery (SELECT Hour(NOW())) to obtain HOUR(NOW());
You can express ( Curdate() + INTERVAL (SELECT Hour(NOW())) hour - INTERVAL 23 hour ) more simply:
CURDATE() + INTERVAL HOUR(NOW()) - 23 HOUR
Or, in my view, more clearly:
DATE_FORMAT(NOW() - INTERVAL 23 HOUR, '%Y-%m-%d %H:00:00')
Your ORDER BY clause is a constant and therefore achieves nothing: did you mean to order by hour?
Therefore:
SELECT HOUR(datetime) AS hour,
AVG(Temperature) AS AVGT
FROM Database.minute
WHERE datetime BETWEEN
DATE_FORMAT(NOW() - INTERVAL 23 HOUR, '%Y-%m-%d %H:00:00')
AND NOW()
GROUP BY hour
ORDER BY hour
Related
Help create a query that will select records from the table for the past period from 6AM until 6AM, the table has a timestamp field.
I will explain, for example:
Now: 2019-06-15 04:44:42
Period: 2019-06-13 06:00:00 - 2019-06-14 06:00:00
Now: 2019-06-15 07:44:42
Period: 2019-06-14 06:00:00 - 2019-06-15 06:00:00
Now: 2019-06-16 01:44:42
Period: 2019-06-14 06:00:00 - 2019-06-15 06:00:00
I think I was not the easiest request:
SELECT * FROM `table` WHERE `timestamp`
BETWEEN
DATE_ADD(DATE(NOW() - INTERVAL '1 6' DAY_HOUR), INTERVAL 6 HOUR)
AND
DATE_ADD(DATE(NOW() - INTERVAL '0 6' DAY_HOUR), INTERVAL 6 HOUR);
How simpler?
You can get the upper range limit with:
date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR
The lower limit would be exactly one day (24 hours) earlier:
date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR - INTERVAL 1 day
So your query could be:
SELECT *
FROM `table` t
WHERE t.timestamp >= date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR - INTERVAL 1 day
AND t.timestamp < date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR
But to avoid code duplication I would rewrite it to:
SELECT t.*
FROM `table` t
CROSS JOIN (
SELECT date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR as upper_limit
) r -- r for "range"
WHERE t.timestamp >= r.upper_limit - INTERVAL 1 day
AND t.timestamp < r.upper_limit
You can though use <= r.upper_limit instead of < r.upper_limit to get the same result as with BETWEEN.
SELECT start, start +interval 24 hour end
FROM ( SELECT date(now())
- interval if(hour(now())>6, 1, 2) day
+ interval 6 hour
as start
) dates;
I have a table with the following data:
I am looking to group the rows into the following:
Within the last day (everything within the last 24 hours)
Within the last 7 days (everything within the last week)
Within the last 30 days (everything within the last month)
The end result for the above rows would look something like:
I can group the records into these brackets right now with:
SELECT (CASE WHEN created_at = CURDATE() THEN '1 Day'
WHEN created_at >= CURDATE() - INTERVAL 6 DAY THEN '7 Days'
WHEN created_at >= CURDATE() - INTERVAL 29 DAY THEN '30 Days'
END) AS Timeframe, COUNT(*) AS Count
FROM my_table
GROUP BY (CASE WHEN created_at = CURDATE() THEN '1 Day'
WHEN created_at >= CURDATE() - INTERVAL 6 DAY THEN '7 Days'
WHEN created_at >= CURDATE() - INTERVAL 29 DAY THEN'30 Days'
END)
But this will prevent individual records from being counted more than once. For example, lines 2 and 3 in the first picture needs to be counted in all three brackets (1 day, 7 days, and 30 days) - while lines 6 through 9 only needs to be counted in the 30 days bracket.
How would you do this with MySQL?
It is easiest to do this as columns, rather than rows:
SELECT SUM(created_at = CURDATE()) as today
SUM(created_at >= CURDATE() - INTERVAL 6 DAY) as last_7_days,
SUM(created_at >= CURDATE() - INTERVAL 29 DAY) as last_30_days,
SUM(created_at < CURDATE() - INTERVAL 29 DAY) as older
FROM my_table;
If you want your response in several rows, instead of just one with several columns, take #Gordon Linoff as your starting point... but perform the queries "one row at at time" (it won't be as efficient, because you visit the table 4 times instead of 1!):
-- Row for the 1 day timeframe
SELECT '1 Day' AS `Timeframe`, SUM(created_at = CURDATE()) AS `Count`
FROM my_table
UNION
-- Row for the 7 days timeframe...
SELECT '7 Days' AS `Timeframe`, SUM(created_at >= CURDATE() - INTERVAL 6 DAY) AS `Count`
FROM my_table
UNION
SELECT '30 Days' AS `Timeframe`, SUM(created_at >= CURDATE() - INTERVAL 29 DAY) AS `Count`
FROM my_table
UNION
SELECT 'Older' AS `Timeframe`, SUM(created_at < CURDATE() - INTERVAL 29 DAY) AS `Count`
FROM my_table ;
If you can use MariaDB instead of MySQL, you can use a WITH, which will allow the query to be efficient again:
WITH stats AS
(
SELECT SUM(created_at = CURDATE()) as today,
SUM(created_at >= CURDATE() - INTERVAL 6 DAY) as last_7_days,
SUM(created_at >= CURDATE() - INTERVAL 29 DAY) as last_30_days,
SUM(created_at < CURDATE() - INTERVAL 29 DAY) as older
FROM my_table
)
-- Convert to rows with negligible overhead
SELECT '1 Day' AS `Timeframe`, today FROM stats
UNION
SELECT '7 Days', last_7_days FROM stats
UNION
SELECT '30 Days', last_30_days FROM stats
UNION
SELECT 'Older', older FROM stats ;
In both cases, you'll get (as of 2017-07-25):
Timeframe | today
:-------- | ----:
1 Day | 0
7 Days | 4
30 Days | 8
Older | 0
dbfiddle here
My current query is:
SELECT COUNT(*) FROM Previous_Appointment WHEREapDateBETWEEN '2017-04-03' AND '2017-04-27'
I need this to run however to just check today's date -7 days, -30 days, etc...
So that it returns the number of instances that have occured.
Try this,
Between today and today -7
SELECT COUNT(*) FROM Previous_Appointment WHERE DATE(apDate) > (NOW() - INTERVAL 7 DAY)
Between today and today -30
SELECT COUNT(*) FROM Previous_Appointment WHERE DATE(apDate) > (NOW() - INTERVAL 30 DAY)
you can use dateadd -7 days
dateadd(day,-7,cast(getdate() as date))
To get count in last week:
select count(*)
from previous_appointment
where apDate between curdate() - interval 7 day and curdate()
To get count in last 30 days:
select count(*)
from previous_appointment
where apDate between curdate() - interval 30 day and curdate()
I am trying to query a timesheet where time span (cycle) is 21 to 20, thus today (10/30/2014) is November.
So, 10/14/2014 is October.
2014-09-21 and 2014-10-20 is one time span
2014-10-21 and 2014-11-20 is one time span
The table is simply storing the date for the timesheet:
id date hours
So, I can specifically say:
SELECT * FROM rapoarte WHERE DATE(ziua) BETWEEN "2014-09-21" AND "2014-10-20"
But I can't figure out how to:
How can I query through this interval for say 1 year (or more)
How can I query for this month?
dynamically
The easiest way is to do date arithmetic. So, for October, you would use:
SELECT *
FROM rapoarte
WHERE month(DATE(ziua) - interval 20 day + interval 1 month) = 10
The idea is to subtract 20 days and add a month. This seems to be the logic for the reporting month.
You can add this as a field:
SELECT *,
date_format(month(DATE(ziua) - interval 20 day + interval 1 month), '%Y-%m') as ReportingMonth
FROM rapoarte
WHERE month(DATE(ziua) - interval 20 day + interval 1 month) = 10
EDIT:
If you want data for this reporting month:
WHERE month(DATE(ziua) - interval 20 day + interval 1 month) = month(DATE(now()) - interval 20 day + interval 1 month) and
year(DATE(ziua) - interval 20 day + interval 1 month) = year(DATE(now()) - interval 20 day + interval 1 month)
How can I change the query below to get 2 hours instead of 1
SELECT DATE_FORMAT(x.time,'%Y-%m-%d %H:00:00')
, avg(Ph) avg_Ph
FROM Ph x where time >= NOW() - INTERVAL 1 DAY
GROUP
BY DATE_FORMAT(x.time,'%Y-%m-%d %H:00:00');
SELECT DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(x.time)/7200)*7200),'%Y-%m-%d %H:00:00') AS `two_hour`
, avg(Ph) avg_Ph
FROM Ph x where time >= NOW() - INTERVAL 1 DAY
GROUP
BY `two_hour`