Helo, this is my query:
MariaDB [PV_Anlage]>
SELECT created_at, verbrauch_ges
FROM pv_metrics
group by DATE(created_at)
ORDER BY ID DESC limit 20;
+---------------------+---------------+
| created_at | verbrauch_ges |
+---------------------+---------------+
| 2025-03-23 00:00:04 | 5628.79 |
| 2025-03-22 00:00:06 | 5622.54 |
| 2025-03-21 00:00:11 | 5615.44 |
| 2025-03-20 00:00:13 | 5609.49 |
| 2025-03-19 00:00:17 | 5605.4 |
| 2025-03-18 00:00:00 | 5600.45 |
| 2025-03-17 00:00:03 | 5591.36 |
| 2025-03-16 00:00:09 | 5585.2 |
| 2025-03-15 00:00:16 | 5578.96 |
| 2025-03-14 00:00:04 | 5571.1 |
| 2025-03-13 00:00:07 | 5560.34 |
| 2025-03-12 00:00:10 | 5550.54 |
| 2025-03-11 00:00:13 | 5540.12 |
| 2025-03-10 00:00:16 | 5534.81 |
| 2025-03-09 00:00:18 | 5528.48 |
| 2025-03-08 00:00:17 | 5521.71 |
| 2025-03-07 00:00:11 | 5515.27 |
| 2025-03-06 00:00:14 | 5510.17 |
| 2025-03-05 00:00:06 | 5504.08 |
| 2025-03-04 00:00:09 | 5497.21 |
+---------------------+---------------+
This is the result, as I'm writing values every 20sec. I've selected the very firste value of the day, so now I need the diffrence between the days. I've tried with LAG() function but I dont understand how to include the function into the general query.
best regardas Frank
Helo, this is my query:
MariaDB [PV_Anlage]>
SELECT created_at, verbrauch_ges
FROM pv_metrics
group by DATE(created_at)
ORDER BY ID DESC limit 20;
+---------------------+---------------+
| created_at | verbrauch_ges |
+---------------------+---------------+
| 2025-03-23 00:00:04 | 5628.79 |
| 2025-03-22 00:00:06 | 5622.54 |
| 2025-03-21 00:00:11 | 5615.44 |
| 2025-03-20 00:00:13 | 5609.49 |
| 2025-03-19 00:00:17 | 5605.4 |
| 2025-03-18 00:00:00 | 5600.45 |
| 2025-03-17 00:00:03 | 5591.36 |
| 2025-03-16 00:00:09 | 5585.2 |
| 2025-03-15 00:00:16 | 5578.96 |
| 2025-03-14 00:00:04 | 5571.1 |
| 2025-03-13 00:00:07 | 5560.34 |
| 2025-03-12 00:00:10 | 5550.54 |
| 2025-03-11 00:00:13 | 5540.12 |
| 2025-03-10 00:00:16 | 5534.81 |
| 2025-03-09 00:00:18 | 5528.48 |
| 2025-03-08 00:00:17 | 5521.71 |
| 2025-03-07 00:00:11 | 5515.27 |
| 2025-03-06 00:00:14 | 5510.17 |
| 2025-03-05 00:00:06 | 5504.08 |
| 2025-03-04 00:00:09 | 5497.21 |
+---------------------+---------------+
This is the result, as I'm writing values every 20sec. I've selected the very firste value of the day, so now I need the diffrence between the days. I've tried with LAG() function but I dont understand how to include the function into the general query.
best regardas Frank
Share Improve this question edited Mar 23 at 17:58 ValNik 6,2191 gold badge7 silver badges15 bronze badges asked Mar 23 at 16:31 DB5FPDB5FP 233 bronze badges 1- The query is illogical. It contains incomplete grouping. Enable ONLY_FULL_GROUP_BY then fix your query. – Akina Commented Mar 23 at 17:47
3 Answers
Reset to default 0In simple case,
if we consider the value of verbrauch_ges
to be monotonously increasing, the smallest (initial) value for the day can be obtained as follows
SELECT min(created_at)created_at
,min(verbrauch_ges) verbrauch_ges
,lag(min(verbrauch_ges))over(order by created_at) prev_verbauch_ges
,min(verbrauch_ges)-coalesce(lag(min(verbrauch_ges))over(order by created_at),0.0) as day_diff
FROM pv_metrics
group by DATE(created_at)
ORDER BY ID DESC limit 20;
for LAG function we use value min(verbrauch_ges)
because LAG function in SELECT clause will be executed after GROUP BY.
This is semantically equivalent to
SELECT created_at, verbrauch_ges
,lag(verbrauch_ges)over(order by created_at) prev_verbauch_ges
FROM (
SELECT min(created_at) as created_at, min(verbrauch_ges) as verbrauch_ges
FROM pv_metrics
group by DATE(created_at)
ORDER BY ID DESC limit 20
)sq
;
MariaDb allows use order by created_at
and order by date(created_at)
in LAG function.
Common case is select target rows from table and INNER JOIN table to this selection
SELECT created_at, verbrauch_ges
,lag(verbrauch_ges)over(order by created_at) prev_verbauch_ges
FROM (
select min(id) id
from pv_metrics
group by DATE(created_at)
ORDER BY min(id) DESC limit 20
) s
inner join pv_metrics m on m.id=s.id
ORDER BY s.ID DESC ;
OR
SELECT created_at, verbrauch_ges
,lag(verbrauch_ges)over(order by created_at) prev_verbauch_ges
FROM (
select min(created_at) created_at
from pv_metrics
group by DATE(created_at)
ORDER BY min(id) DESC limit 20
) s
inner join pv_metrics m on m.created_at=s.created_at
ORDER BY s.ID DESC ;
Examples
Your query exploits the notorious MySQL extension to GROUP BY. It means this baffling pile of uncertainty.
SELECT created_at, ANY_VALUE(verbrauch_ges)
FROM pv_metrics
group by DATE(created_at)
ORDER BY ANY_VALUE(ID) DESC limit 20
ANY_VALUE)_ tells MySQL it can arbitrarily choose some value from the group. You get unpredictable values from that.
This makes it hard to guess your intent from your example.
It sounds like you want a result set with one row per calendar day, showing the difference between the verbrauch_ges
values with the earliest created_at
datestamp for that day
Here's how you do that.
First you want a result set with the earliest created_at
time on each day.
SELECT MIN(created_at) created_at
FROM pv_metrics
GROUP BY DATE(created_at)
Then you want to extract the values, one per day.
SELECT DATE(pv_metrics.created_at) tag, AVG(verbracht_ges) erste_verbraucht_ges
FROM pv_metrics
JOIN (
SELECT MIN(created_at) created_at
FROM pv_metrics
GROUP BY DATE(created_at)
) firsts ON pv_metrics.created_at = firsts.created_at
GROUP_BY DATE(pv_metrics.created_at)
The AVG() is there to do something reasonable if you have more than one observation at precisely the same created_at
time. You could also use MAX() or MIN().
Finally, now that you have a virtual table with columns tag
and erste_verbraucht_ges
you can do a LAG select on it to get your desired result.
created_at | verbrauch_ges | prev_verbauch_ges | day_diff |
---|---|---|---|
2025-03-23 00:00:04 | 5628.79 | 5622.54345703125 | 6.2431640625 |
2025-03-22 00:00:06 | 5622.54 | 5615.43798828125 | 7.10546875 |
2025-03-21 00:00:11 | 5615.44 | 5609.4912109375 | 5.94677734375 |
2025-03-20 00:00:13 | 5609.49 | 5605.40380859375 | 4.08740234375 |
2025-03-19 00:00:17 | 5605.4 | 5600.44970703125 | 4.9541015625 |
2025-03-18 00:00:00 | 5600.45 | 5591.36279296875 | 9.0869140625 |
2025-03-17 00:00:03 | 5591.36 | 5585.2001953125 | 6.16259765625 |
2025-03-16 00:00:09 | 5585.2 | 5578.9580078125 | 6.2421875 |
2025-03-15 00:00:16 | 5578.96 | 5571.10498046875 | 7.85302734375 |
2025-03-14 00:00:04 | 5571.1 | 5560.3427734375 | 10.76220703125 |
2025-03-13 00:00:07 | 5560.34 | 5550.5400390625 | 9.802734375 |
2025-03-12 00:00:10 | 5550.54 | 5540.1171875 | 10.4228515625 |
2025-03-11 00:00:13 | 5540.12 | 5534.80908203125 | 5.30810546875 |
2025-03-10 00:00:16 | 5534.81 | 5528.48046875 | 6.32861328125 |
2025-03-09 00:00:18 | 5528.48 | 5521.70703125 | 6.7734375 |
2025-03-08 00:00:17 | 5521.71 | 5515.27392578125 | 6.43310546875 |
2025-03-07 00:00:11 | 5515.27 | 5510.17431640625 | 5.099609375 |
2025-03-06 00:00:14 | 5510.17 | 5504.083984375 | 6.09033203125 |
2025-03-05 00:00:06 | 5504.08 | 5497.21240234375 | 6.87158203125 |
2025-03-04 00:00:09 | 5497.21 | 5489.51904296875 | 7.693359375 |
SELECT min(created_at)created_at
,min(verbrauch_ges) verbrauch_ges
,lag(min(verbrauch_ges))over(order by created_at) prev_verbauch_ges
,min(verbrauch_ges)-coalesce(lag(min(verbrauch_ges))over(order by created_at),0.0) as day_diff
FROM pv_metrics
group by DATE(created_at)
ORDER BY ID DESC limit 20;
That's the answer or query I've needed.
Thanks