SQL query to get AVG from columns and GROUP BY - mysql

I have a table like this which consists of several climatic measures (rain rates, temps, etc.)
mysql> select rain_rate, temperature, datetime from weather limit 10;
+--------------+---------------+----------------------+
| rain_rate | temperature | datetime |
+--------------+---------------+----------------------+
| 5.0000000000 | 24.4000000000 | 2017-02-08 16:00:56 |
| 1.0000000000 | 22.4000000000 | 2017-02-06 12:10:36 |
| 2.0000000000 | 28.7000000000 | 2017-02-02 13:57:15 |
| 5.0000000000 | 24.7000000000 | 2017-02-01 14:14:16 |
| 1.0000000000 | 16.1000000000 | 2017-01-08 06:01:26 |
| 2.0000000000 | 18.2000000000 | 2017-01-12 05:10:43 |
| 3.0000000000 | 11.9000000000 | 2017-01-10 06:20:54 |
| 4.0000000000 | 16.8000000000 | 2017-01-25 16:10:14 |
| 5.0000000000 | 24.4000000000 | 2016-12-18 23:10:56 |
| 4.0000000000 | 26.6000000000 | 2016-12-30 09:03:54 |
...
As can be seen, timestamps (datetime field) does not follow any pattern.
I want to get the last 24 average values of temperature and rain_rate by hour, and a column with the numerical value of the associated hour, in 24-hour format, ordered by hour asc.
As an example, if I executed the query today at 18:30 pm, it should return these 24 rows:
+-----------------+------------------+-------+
| avg(rain_rate) | avg(temperature) | hour |
+-----------------+------------------+-------+
| 3.5000000000 | 23.1000000000 | 19 | |
| 1.0000000000 | 22.6000000000 | 20 | |
| 3.5000000000 | 24.7000000000 | 21 | |-> hours of "yesterday"
| 4.5000000000 | 23.8000000000 | 22 | |
...
| 2.0000000000 | 26.3000000000 | 13 | |
| 1.5000000000 | 21.6000000000 | 14 | |
| 7.0000000000 | 23.4000000000 | 15 | |-> hours of "today"
| 2.5000000000 | 21.4000000000 | 16 | |
| 7.0000000000 | 21.2000000000 | 17 | |
| 3.0000000000 | 25.3000000000 | 18 | |
My best try so far:
select avg(rain_rate), avg(temperature), hour(datetime) as hour
from weather
where (datetime >= now() - interval 24 hour)
group by hour(datetime)
order by max(datetime) asc
It looks like that query returns the correct average values for the fields, but hour field does not seem to be ordered like I need nor corresponding to the mean values...
Any help is much appreciated.
Thanks in advance.

You want to average by hour for the past 24 hours.
Ok. Here is one way:
select date(datetime), hour(datetime),
avg(rain_rate), avg(temperature)
from weather
where (datetime >= now() - interval 24 hour)
group by date(datetime), hour(datetime)
order by min(datetime);
Note: 24 hours from the current time might be a little weird. You could get 25 rows of records (with two partial hours). You may want this where:
where datetime < curdate() + interval hour(now()) hour and
datetime >= curdate() + interval hour(now()) - 24 hour

I suppose you must try order by datetime.
The query must be like:
select avg(rain_rate), avg(temperature), hour(datetime) as hour
from weather
where (datetime >= now() - interval 24 hour)
group by hour(datetime)
order by datetime asc;
I hope i was help.

Related

Mysql - sum time difference and group per hour

I've ask recently question about grouping data per hour, but I will try to extend and explain more.
Currently I've managed to organized the structure like this:
ChangeDate | ChangeTime | timediff |
+------------+------------+----------+
| 2020-10-07 | 19:51:26 | 46 |
| 2020-10-07 | 19:53:13 | 48 |
| 2020-10-07 | 19:54:20 | 21 |
| 2020-10-07 | 19:54:56 | 105 |
| 2020-10-07 | 20:13:53 | 209 |
| 2020-10-07 | 20:52:28 | 45 |
| 2020-10-07 | 20:53:43 | 210 |
| 2020-10-07 | 20:56:08 | 258 |
| 2020-10-07 | 20:59:43 | 13 |
The desire result is to group the data per HOUR of ChangeTime column and SUM timediff which is already done(those are seconds)
So the new table structure would looks like this:
| ChangeDate | ChangeTime | timediff |
+------------+------------+----------+
| 2020-10-07 | 19:51:26 or 19-20 if possible | 48 + 46 + 21 + 105 |
| 2020-10-07 | 20:13:53 or 20-21 | 209 + 45 + 210 + 258 + 13 |
Second column it's optiona XX-YY format for example 19-20, cuz there can stay any particular value from that interval, again for this example 19:51:26...
Seconds also can stay, jus i need the sum i will convert them to minutes:seconds format...
This is so far what I've tried:
select DISTINCT MAX(t.ChangeDate) ChangeDate, MAX(t.ChangeTime) ChangeTime , t.timediff
FROM
(
select DISTINCT ChangeDate, HOUR(ChangeTime) ChangeTime, SUM(TimeDiff(CurrentTime,ChangeTime)) as timediff
from pins
where serial="6381872047252543"
and CurrentDate >= '2020-10-07' and CurrentDate <= '2020-10-08'
group by ChangeDate, ChangeTime
) t
group by t.timediff
order by ChangeDate, ChangeTime asc
Br,
You can use hour():
select changedate, hour(changetime) changehour,
sum(timediff(currenttime,changetime)) as sum_timediff
from pins
group by changedate, changehour

How to query records where one field greater than another by x days?

I have a table like:
+----+------------+------------+
| id | expiry | timestamp |
+----+------------+------------+
| 1 | 2018-11-29 | 2018-11-01 |
| 2 | 2018-12-27 | 2018-11-01 |
| 3 | 2019-01-31 | 2018-11-01 |
| 4 | 2018-11-29 | 2018-11-01 |
| 5 | 2018-12-27 | 2018-11-01 |
+----+------------+------------+
How can I query all records for which expiry is less than 30 days from timestamp? i.e.
timestamp + 30 days > expiry
I would recommend:
where expiry < timestamp + interval 30 day
you can try this
SELECT * FROM table_name WHERE DATE_ADD(TIMESTAMP , INTERVAL 30 DAY) > expiry;

Calculating month over month numbers

I searched around and found solutions, but they didn't work with MySQL because they used functions from other software.
I'm trying to show month-over-month growth for the current year (starting January), though knowing how to check within the past year might come in handy in the future as well.
What the "orders" table might look like:
+-----------+-------+
| Month | Sales |
+-----------+-------+
| 1-1-2017 | 3 |
| 1-5-2017 | 9 |
| 2-16-2017 | 10 |
| 2-16-2017 | 13 |
| 3-7-2017 | 25 |
| 4-29-2017 | 22 |
+-----------+-------+
What I want the query result to look like:
+----------+-------+--------+
| Month | Sales | Growth |
+----------+-------+--------+
| January | 12 | |
| February | 23 | 91.66% |
| March | 25 | 8.69% |
| April | 22 | -12% |
+----------+-------+--------+
Is there a simple way to do this?
You can do something like that:
SELECT
thisMonth.MonthOnly,
SUM(thisMonth.Sales) AS ThisMonthSales,
(SUM(thisMonth.Sales) / SUM(lastMonth.Sales) - 1) * 100 AS Growth
FROM
(
SELECT STR_TO_DATE(DATE_FORMAT(Month, '%Y%m01'), '%Y%m%d') AS MonthOnly,
SUM(Sales) AS Sales
FROM orders
GROUP BY DATE_FORMAT(Month, '%Y%m01')
) thisMonth
LEFT OUTER JOIN
(
SELECT STR_TO_DATE(DATE_FORMAT(DATE_ADD(Month, INTERVAL 1 MONTH), '%Y%m01'), '%Y%m%d') AS MonthOnly,
SUM(Sales) AS Sales
FROM orders
GROUP BY DATE_FORMAT(Month, '%Y%m01')
) lastMonth
ON thisMonth.MonthOnly = lastMonth.MonthOnly
GROUP BY thisMonth.MonthOnly

MySQL: How to get data id for 1 week starting on Monday

-------------------------
| idproduct | date |
|-------------------------|
| idp001 | 2017-05-01 |
| idp003 | 2017-05-05 |
| idp005 | 2017-05-07 |
| idp007 | 2017-05-08 |
| idp010 | 2017-05-09 |
-------------------------
I have try this code :
SELECT * FROM product where date between date_sub(now(),INTERVAL 1 week) and now()
it result :
-------------------------
| idproduct | date |
|-------------------------|
| idp003 | 2017-05-05 |
| idp005 | 2017-05-07 |
| idp007 | 2017-05-08 |
| idp010 | 2017-05-09 |
-------------------------
but i want result like this and first day of week monday
-------------------------
| idproduct | date |
|-------------------------|
| idp001 | 2017-05-01 |
| idp003 | 2017-05-05 |
| idp005 | 2017-05-07 |
-------------------------
You can use weekday():
where date >= curdate() - interval 7 + weekday(curdate()) day and
date < curdate() - interval weekday(curdate()) day
weekday() returns 0 on Monday and then increments for subsequent days. This code uses curdate() because it explicitly has no time component. And, it prefers >= and < over between. The time component can cause unexpected results using between, so I just never use it for date/times.

Selecting last day of every month?

I have the following data in MySQL:
+------------+-------+
| myDATE | delta |
+------------+-------+
| 2015-08-29 | 12 |
| 2015-08-30 | 12 |
| 2015-08-31 | 10 |
| 2015-09-01 | 0 |
| 2015-09-02 | 0.15 |
+------------+-------+
I want to run a query that will select the last day of each month and show the data. I thought I had it working but its not showing yesterdays data.
select mydate, delta from data group by date_format(mydate, '%Y-%m');
Results in:
+------------+-------+
| mydate | delta |
+------------+-------+
| 2015-08-29 | 12 |
| 2015-09-01 | 0 |
+------------+-------+
What am I missing?
I'm looking for it to return this: (ie. The last day of each month on record)
+------------+-------+
| myDATE | delta |
+------------+-------+
| 2015-08-31 | 10 |
| 2015-09-02 | 0.15 |
+------------+-------+
select last_day(mydate), sum(delta) from data group by last_day(mydate)
last_day is a function which returns the last day of the month the given date
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_last-day
to answer the updated question
select data.`myDate`, data.delta from data inner join
(select max(`myDate`) myDate from data group by date_format(mydate, '%Y-%m')) a
on a.myDate = data.myDate