Reputation: 35
Hello I am having a Table, that is filled by my home automation. I princinle there are all the values in just one table. Some entries are made by a statistical modul. It calculates the monthly water consumption. Now I want to create a query, that give a mounthly view of the comsumption for each year.
Like:
|Month|2018|2019|
|Jan..|7.3 |6.8|
|Feb |5.9 |7.8|....
The query for one year is:
SELECT
monthname(TIMESTAMP) Monat,
VALUE '2018'
FROM
fhem.history acht
WHERE
DEVICE LIKE 'Wasserverbrauch'
AND READING LIKE 'statStateMonthLast'
AND year(TIMESTAMP) = 2018
But how can I Join the values for 2019? Can someone point me to the right direction?
Thanks,
Ruediger
Upvotes: 1
Views: 167
Reputation: 1271151
This is a variation of GMB's answer. But if you want the results in chronological order by month, then you need to include that in the query:
SELECT MONTHNAME(timestamp) as Monat,
SUM(CASE WHEN YEAR(timestamp) = 2018 THEN value END) value_2018,
SUM(CASE WHEN YEAR(timestamp) = 2019 THEN value END) as value_2019
FROM fhem.history acht
WHERE device = 'Wasserverbrauch' AND
reading = 'statStateMonthLast' AND
timestamp >= '2018-01-01' AND
timestamp < '2020-01-01'
GROUP BY MONTHNAME(timestamp), MONTH(timestamp)
ORDER BY MONTH(timestamp);
Upvotes: 0
Reputation: 222702
You can do conditional aggregation:
SELECT
MONTHNAME(timestamp) Monat,
MAX(CASE WHEN timestamp >= '2018-01-01' AND timestamp < '2019-01-01' THEN value END) `2018`,
MAX(CASE WHEN timestamp >= '2019-01-01' AND timestamp < '2020-01-01' THEN value END) `2019`
FROM fhem.history acht
WHERE
device = 'Wasserverbrauch'
AND reading = 'statStateMonthLast'
AND timestamp >= '2018-01-01'
AND timestamp < '2020-01-01'
GROUP BY MONTHNAME(timestamp)
Notes:
the LIKE
conditions in the WHERE
clause are actually equivalent to =
s, since there is no wildcard in the right operand; I changed them accordingly
it is usually a better practice to do explicit datetime range comparison rather than using date functions (in your case, year()
), since the latter prevents the use of an index
if you need to handle multiple recors per month (which does not seem to be the case based on your existing query), then you should use another aggregate function to get a more sensible result (sum()
or avg()
)
Upvotes: 1
Reputation: 938
You can use EXTRACT() function to get year/month from timestamp and conditional expression to put all in columns.
I think table with month numbers and names would be useful for outer join.
SELECT
m.`month`,
SUM(IF(h.`year_no`=2019, h.`value`, 0)) AS `2019`,
SUM(IF(h.`year_no`=2020, h.`value`, 0)) AS `2020`
FROM `monthes` AS m
LEFT JOIN (
SELECT
EXTRACT(YEAR FROM `timestamp`) AS `year_no`,
EXTRACT(MONTH FROM `timestamp`) AS `month_no`,
`value`
FROM `history`
) AS h ON h.`month_no` = m.`id`
GROUP BY m.`id`
I used GROUP BY month IDs, so result will be implicitely ordered by month number, not by month name.
https://www.db-fiddle.com/f/78LQtak6GwkDS8pzredroQ/0
I did NOT use additional filters here for bravity, but if you need them, add WHERE...
into nested subquery right bellow FROM history
.
Upvotes: 0