Mysql - sum time difference and group per hour - mysql

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

Related

Calculating difference of two values and sorting based on the result with mysql

game table:
| id | group_id | user_id | last_update | bonus |
| 1 | 4 | 1 | 2017-01-22 00:06:10 | 0 |
| 2 | 4 | 1 | 2017-01-12 00:11:34 | 300 |
| 3 | 4 | 1 | 2017-01-02 00:30:44 | -111 |
| 3 | 4 | 1 | 2017-02-02 00:21:44 | 4330 |
| 3 | 4 | 6 | 2017-01-02 01:02:27 | 30 |
| 3 | 4 | 6 | 2017-01-07 11:22:37 | 40 |
| 3 | 4 | 6 | 2017-03-04 11:22:37 | 0 |
I want to calculate bonus of the current date minus the bonus of the first day of the current month for every user of a given group.
The wanted output:
| user_id | january (last day bonus - first day bonus) |
| 5 | 1400 |
| 19 | 1377 |
| 1 | 806 |
| 14 | 140 |
| 50 | 14 |
Currently, I'm getting bonuses of the given month (1 query), calculating the difference between the last and first ones. I have 4000 users, so I'm performing 4000 queries to do what I want and it's too slow.
Is it possible to do that with only mysql?
Perhaps the "most correct" way would be to use variables or complex subqueries. However, another way that should work is to use group_concat()/substring_index():
select user_id, date_format(last_update, '%Y-%m') as yyyymm,
substring_index(group_concat(bonus order by last_update desc), ',', 1) as last_bonus,
substring_index(group_concat(bonus order by last_update asc), ',', 1) as first_bonus,
(substring_index(group_concat(bonus order by last_update desc), ',', 1) -
substring_index(group_concat(bonus order by last_update asc), ',', 1)
) as bonus_diff
from t
group by user_id, yyyymm;
Note that this converts the bonus to a string -- and then back again to a number for the calculation. That is why I might call this "quick-and-dirty" or a "hack". However, it should work and the conversions are safe because the values start out as numbers.
Second, group_concat() has a default limit of 1024 bytes. That should not be a problem for these aggregations -- unless you have hundreds of rows for a user within a month.

SQL query to get AVG from columns and GROUP BY

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.

Finding the MAX value for each day in a month over multiple years in MySQL [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 6 years ago.
I've got a database full of weather data...specifically the date, max temp, min temp, and daily rainfall for more than 100 years. I'm trying to find the maximum temperature for each day and the specific date that it occurred over the entire 100+ years.
My table is set up similar to below...
+-------+------------+------+------+------+
| id | date | thi | tlo | rain |
+-------+------------+------+------+------+
| 42856 | 2016-01-01 | 49 | 39 | 0.00 |
| 42857 | 2016-01-02 | 51 | 38 | 0.00 |
| 42858 | 2016-01-03 | 60 | 37 | 0.00 |
| 42859 | 2016-01-04 | 54 | 32 | 0.00 |
| 42860 | 2016-01-05 | 47 | 32 | 0.00 |
+-------+------------+------+------+------+
5 rows in set (0.01 sec)
I want to find the max(thi) for each day of the year and the date in which it occurred. This data goes back to 1899 so there are 117 January's in the database and so on for each year.
I have come up with the following so far...
select date, max(thi),
-> DAY(date)
-> from dfw where MONTH(date)='01'
-> group by DAY(date);
+------------+----------+-----------+
| date | max(thi) | DAY(date) |
+------------+----------+-----------+
| 1899-01-01 | 83 | 1 |
| 1899-01-02 | 78 | 2 |
| 1899-01-03 | 84 | 3 |
| 1899-01-04 | 81 | 4 |
| 1899-01-05 | 82 | 5 |
| 1899-01-06 | 79 | 6 |
| 1899-01-07 | 83 | 7 |
| 1899-01-08 | 88 | 8 |
| 1899-01-09 | 82 | 9 |
| 1899-01-10 | 79 | 10 |
| 1899-01-11 | 83 | 11 |
| 1899-01-12 | 82 | 12 |
| 1899-01-13 | 78 | 13 |
| 1899-01-14 | 79 | 14 |
| 1899-01-15 | 80 | 15 |
| 1899-01-16 | 81 | 16 |
| 1899-01-17 | 79 | 17 |
| 1899-01-18 | 80 | 18 |
| 1899-01-19 | 84 | 19 |
| 1899-01-20 | 83 | 20 |
| 1899-01-21 | 79 | 21 |
| 1899-01-22 | 85 | 22 |
| 1899-01-23 | 88 | 23 |
| 1899-01-24 | 82 | 24 |
| 1899-01-25 | 84 | 25 |
| 1899-01-26 | 82 | 26 |
| 1899-01-27 | 81 | 27 |
| 1899-01-28 | 85 | 28 |
| 1899-01-29 | 84 | 29 |
| 1899-01-30 | 86 | 30 |
| 1899-01-31 | 93 | 31 |
+------------+----------+-----------+
31 rows in set (0.01 sec)
This gives me the maximum for each day in January which is good...but I need the date on which it occurred. For some reason all I am getting is 1899.
For example on January 31...the max(thi) is 93 but it occurred on 1911-01-31. There are also times in which the max(thi) could have occurred in multiple years. On January 30...the max(thi) is 86 which occurred on 1906-01-30 and 1994-01-30.
Is there a way to do this in MySQL or am I just out of luck? Thanks in advance!
The value returned for date expression in your SELECT is indeterminate. MySQL is free to return a date value from any row in the group. (Other databases would throw an error with this query. A MySQL specific extension to GROUP BY allows the query to run, but we can get MySQL to more closely conform to the SQL standard, and throw an error with this query, by including ONLY_FULL_GROUP_BY in sql_mode.)
You've got a good start.
SELECT DATE_FORMAT(n.date,'%m%d') AS mmdd
, MAX(n.thi) AS max_thi
FROM dfw
GROUP BY DATE_FORMAT(n.date,'%m%d')
To get the year, there's a couple of approaches. One is to use the query as an inline view, and join to the original table to find a matching row, one with the same month and day, and the same thi value.
You can use either the MAX() or MIN() aggregate to get the latest or earliest date.
SELECT m.mmdd
, m.thi
, MAX(t.date) AS latest_date
, MIN(t.date) AS earliest_date
FROM (
SELECT DATE_FORMAT(n.date,'%m%d') AS mmdd
, MAX(n.thi) AS thi
FROM dfw
GROUP BY DATE_FORMAT(n.date,'%m%d')
) m
JOIN dfw t
ON t.thi = m.thi
AND DATE_FORMAT(t.date,'%m%d') = m.mmdd
GROUP BY m.mmdd
ORDER BY m.mmdd
If you want to return all years for a given mmdd that the highest thi occurred, remove the GROUP BY clause, and the aggregate from around t.date
SELECT m.mmdd
, m.thi
, t.date
FROM (
SELECT DATE_FORMAT(n.date,'%m%d') AS mmdd
, MAX(n.thi) AS thi
FROM dfw
GROUP BY DATE_FORMAT(n.date,'%m%d')
) m
JOIN dfw t
ON t.thi = m.thi
AND DATE_FORMAT(t.date,'%m%d') = m.mmdd
ORDER BY m.mmdd, t.date
As another alternative, to get the earliest date that thi occurred, you could use a correlated subquery in the SELECT list:
SELECT DATE_FORMAT(n.date,'%m%d') AS mmdd
, MAX(n.thi) AS thi
, ( SELECT t.date
FROM dfw t
WHERE DATE_FORMAT(t.date,'%m%d') = DATE_FORMAT(n.date,'%m%d')
AND t.thi = n.thi
ORDER BY t.date
LIMIT 0,1
) AS earliest_date
FROM dfw n
GROUP BY DATE_FORMAT(n.date,'%m%d')
ORDER BY DATE_FORMAT(n.date,'%m%d')

MySQL: Getting the most counted same-value entry (statistical mode) per hour within a datetime range

I have a table like this:
+--------+---------+----------------------+--------------+----------+
| idadata | value_r | date_r | idparameter | idnode |
+--------+-----------+-----------------------+--------------+--------+
| 54620 | 66.6627 | 2014-10-16 12:01:09 | 46 | 9 |
| 54621 | 19.4953 |2014-10-16 12:01:09 | 40 | 9 |
| 54622 | 19.9384 |2014-10-16 12:01:09 | 47 | 9 |
| 54623 | 163.849 | 2014-10-16 12:01:09 | 43 | 9 |
| 54624 | 67.9257 | 2014-10-16 12:02:09 | 44 | 9 |
| 54625 | 315 | 2014-10-16 12:02:09 | 42 | 9 |
| 54626 | 0.699 | 2014-10-16 12:02:09 | 41 | 9 |
| 54627 | 67.9257 | 2014-10-16 12:03:09 | 46 | 9 |
| 54628 | 19.2308 | 2014-10-16 12:03:09 | 40 | 9 |
| 54629 | 11.207 | 2014-10-16 12:03:09 | 47 | 9 |
| 54630 | 118.743 | 2014-10-16 12:03:09 | 43 | 9 |
| 54631 | 292.5 | 2014-10-16 12:03:09 | 42 | 9 |
+---------+----------+----------------------+---------------+-------+
I need to get the statistical mode or the value_r that repeats the most for a given idparameter and idnode in a given datime interval each hour. I have managed to get the mode when I set the datetime difference for 1 hour manually. However, when I try to group by hour or time difference it doesn't work and I end up with mode of the whole Start-End datetime and not group by hours.
So far this is my code:
select value_r , date_r , max(counter_v) from
(SELECT iddata, value_r,date_r ,count( value_r ) counter_v
FROM wsnca.data dat
where dat.idnode=9 and dat.idparameter=42 and
( dat.date_r between ('2014-10-16 12:00:00') and ('2014-10-16 13:00:00') )
group by value_r
order by counter_v DESC) T;
Result:
+----------+----------------------+---------------+
| value_r | date_r | max(counter_v)|
+-----------+----------------------+--------------+
| 270 | 2014-10-16 12:03:09 | 7 |
+-----------+-----------------------+--------------+
However, the result I'm looking for would be like this:
+----------+----------------------+---------------+
| value_r | date_r | max(counter_v)|
+-----------+----------------------+--------------+
| 270 | 2014-10-16 12:00:00 | 7 |
+-----------+-----------------------+--------------+
| 90 | 2014-10-16 13:00:00 | 4 |
+-----------+-----------------------+--------------+
| 45 | 2014-10-16 14:00:00 | 9 |
+-----------+-----------------------+--------------+
| 180 | 2014-10-16 15:00:00 | 8 |
+-----------+-----------------------+--------------+
As I said before, I don't know how to group that by one hour time interval and reading from the query round at the hour datetime as in the desired table.
I know I could do it in the PHP doing several queries but would prefer to do it in the one query.
You can number the count for each value_r per hour starting with #1 for the highest count, #2 for the 2nd highest and so on and then only keep #1 rows, which will be the modes for each hour.
select date_hour, value_r, cnt from (
select * ,
#rowNum := IF(date_hour = #prevDateHour,#rowNum+1,1) rowNum,
#prevDateHour := date_hour
from (
select value_r, hour(date_r) date_hour, count(*) cnt
from wsnca.data dat
where dat.idnode=9 and dat.idparameter=42
group by value_r, hour(date_r)
) t1 order by date_hour, cnt desc
) t1 where rowNum = 1
change group by value_r into group by value_r, date_r I think that should make it
EDIT Better Response for what you want to achieve
select value_r , DATE_FORMAT(date_r, '%Y-%m-%d %H') as formatted_date, max(counter_v) from
(SELECT iddata, value_r,date_r ,count( value_r ) counter_v
FROM wsnca.data dat
where dat.idnode=9 and dat.idparameter=42 and
( dat.date_r between ('2014-10-16 12:00:00') and ('2014-10-16 13:00:00') )
group by value_r, formatted_date
order by counter_v DESC) T

get amount between range [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 8 years ago.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Improve this question
This a simple my table
+-----------+----------------+-----------+
| id | date | meter |
------------+----------------+-----------+
| 1 | 2103-11-01 | 5 |
| 2 | 2103-11-10 | 8 |
| 4 | 2103-11-14 | 10 |
| 6 | 2103-11-20 | 18 |
| 7 | 2103-11-25 | 25 |
| 10 | 2103-11-29 | 30 |
+-----------+----------------+-----------+
how do I get the results to the use of meters between two ranges of the results of recording time,
like bellow
+----------------+----------------+-------+-----+--------+
| date1 | date2 | start | end | amount |
+----------------+----------------+-------+-----+--------+
| 2013-11-01 | 2013-11-10 | 5 | 8 | 3 |
| 2013-11-10 | 2013-11-14 | 8 | 10 | 2 |
| 2013-11-14 | 2013-11-20 | 10 | 18 | 8 |
| 2013-11-20 | 2013-11-25 | 18 | 25 | 7 |
| 2013-11-25 | 2013-11-29 | 25 | 30 | 5 |
+----------------+----------------+-------+-----+--------+
Edit:
I got it:
select meters1.date as date1, min(meters2.date) as date2, meters1.meter as start,
meters2.meter as end, (meters2.meter - meters1.meter) as amount
from meters meters1, meters meters2 where meters1.date < meters2.date
group by date1;
Outputs:
+------------+------------+-------+-----+--------+
| date1 | date2 | start | end | amount |
+------------+------------+-------+-----+--------+
| 2013-11-01 | 2013-11-10 | 5 | 8 | 3 |
| 2013-11-10 | 2013-11-14 | 8 | 10 | 2 |
| 2013-11-14 | 2013-11-20 | 10 | 18 | 8 |
| 2013-11-20 | 2013-11-25 | 18 | 25 | 7 |
| 2013-11-25 | 2013-11-29 | 25 | 30 | 5 |
+------------+------------+-------+-----+--------+
Original Post:
This is most of the way there:
select meters1.date as date1, meters2.date as date2, meters1.meter as start,
meters2.meter as end, (meters2.meter - meters1.meter) as amount
from meters meters1, meters meters2 having date1 < date2 order by date1;
It outputs:
+------------+------------+-------+-----+--------+
| date1 | date2 | start | end | amount |
+------------+------------+-------+-----+--------+
| 2013-11-01 | 2013-11-10 | 5 | 8 | 3 |
| 2013-11-01 | 2013-11-20 | 5 | 18 | 13 |
| 2013-11-01 | 2013-11-29 | 5 | 30 | 25 |
| 2013-11-01 | 2013-11-14 | 5 | 10 | 5 |
| 2013-11-01 | 2013-11-25 | 5 | 25 | 20 |
| 2013-11-10 | 2013-11-20 | 8 | 18 | 10 |
| 2013-11-10 | 2013-11-29 | 8 | 30 | 22 |
| 2013-11-10 | 2013-11-14 | 8 | 10 | 2 |
| 2013-11-10 | 2013-11-25 | 8 | 25 | 17 |
| 2013-11-14 | 2013-11-25 | 10 | 25 | 15 |
| 2013-11-14 | 2013-11-20 | 10 | 18 | 8 |
| 2013-11-14 | 2013-11-29 | 10 | 30 | 20 |
| 2013-11-20 | 2013-11-25 | 18 | 25 | 7 |
| 2013-11-20 | 2013-11-29 | 18 | 30 | 12 |
| 2013-11-25 | 2013-11-29 | 25 | 30 | 5 |
+------------+------------+-------+-----+--------+
If it's SQL server try it this way
WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY date) rnum
FROM table1
)
SELECT c.date date1, p.date date2, c.meter [start], p.meter [end], p.meter - c.meter amount
FROM cte c JOIN cte p
ON c.rnum = p.rnum - 1
Here is SQLFiddle demo
If it's MySQL then you can do
SELECT date1, date2, meter1, meter2, meter2 - meter1 amount
FROM
(
SELECT #d date2, date date1, #m meter2, meter meter1, #d := date, #m := meter
FROM table1 CROSS JOIN (SELECT #d := NULL, #m := NULL) i
ORDER BY date DESC
) q
WHERE date2 IS NOT NULL
ORDER BY date1
Here is SQLFiddle demo
Output in both cases:
| DATE1 | DATE2 | START | END | AMOUNT |
|------------|------------|-------|-----|--------|
| 2103-11-01 | 2103-11-10 | 5 | 8 | 3 |
| 2103-11-10 | 2103-11-14 | 8 | 10 | 2 |
| 2103-11-14 | 2103-11-20 | 10 | 18 | 8 |
| 2103-11-20 | 2103-11-25 | 18 | 25 | 7 |
| 2103-11-25 | 2103-11-29 | 25 | 30 | 5 |
MySql
SELECT DATES.date1,
DATES.date2,
m1.meter as start,
m2.meter as end,
m2.meter - m1.meter as amount
FROM
(SELECT date as date1,
(SELECT min(date)
FROM tableName t2
WHERE t2.date > t1.date) as date2
FROM tableName t1
)DATES,
tableName m1,
tableName m2
WHERE DATES.date2 IS NOT NULL
AND m1.date = DATES.date1
AND m2.date = DATES.date2
ORDER BY DATES.date1
sqlFiddle here
in MS-SQL SERVER 2002 change the word end to "end" as it complains about syntax near end
You haven't made it clear whether you're really using mySQL or SQL Server but I'm posting a solution that works for SQL 2008 and above. Might work for 2005 but I can't test that.
-- Set up a temp table with sample data
DECLARE #testData AS TABLE(
id int,
dt date,
meter int)
INSERT #testData(id, dt, meter) VALUES
(1, '2013-11-01', 5)
,(2, '2013-11-10', 8)
,(4, '2013-11-14', 10)
,(6, '2013-11-20', 18)
,(7, '2013-11-25', 25)
,(10, '2013-11-29',30)
---------------------------------------------
-- Begin SQL Server solution
;WITH cte AS (
SELECT
ROW_NUMBER() OVER (ORDER BY id) AS rownum
,id
,dt
,meter
FROM
#testData AS [date2]
)
SELECT
t1.id
,t1.dt AS [date1]
,t2.dt AS [date2]
,t1.meter AS [start]
,t2.meter AS [end]
,t2.meter - t1.meter AS [amount]
FROM
cte t1
LEFT OUTER JOIN cte t2 ON (t2.rownum = t1.rownum + 1)
WHERE
t2.dt IS NOT NULL
If you're using MySQL, then a self-join will work well here. Join the table to itself, using an ON clause to make sure you don't join the same record to itself. This will give you ((N * N) - N) permutations of your data, where N is the number of original rows.
SELECT
...
FROM
tableName first
JOIN
tableName second
ON first.id != second.id
Then, it's all about SELECTing the right stuff (including the calculation of the difference between the two meter values). To get the columns in the result set you posted, you'd probably want to SELECT:
first.date AS date1,
second.date AS date2,
first.meter AS start,
second.meter AS end,
ABS(first.meter - second.meter) AS amount
Edit
Ah, I see. I'd envisioned something like a inter-city mileage chart that you used to see on road maps (where you'd have the same cities in the rows and columns, and the cell in the intersection would indicate the number of miles between those two cities.
But it looks like you just want to compare values from one date to the next. If that's the case, you can take advantage of the way MySQL handles GROUPing and ORDERing... but be careful, because I'm not sure this is guaranteed:
mysql> SELECT
table1.date AS date1,
table2.date AS date2,
table1.meter AS start,
table2.meter AS end,
ABS(table1.meter - table2.meter) AS amount
FROM tableName table1
JOIN tableName table2
WHERE table2.date > table1.date
GROUP BY table1.date
ORDER BY table2.date - table1.date;
+---------------------+---------------------+-------+------+--------+
| date1 | date2 | start | end | amount |
+---------------------+---------------------+-------+------+--------+
| 2103-11-25 00:00:00 | 2103-11-29 00:00:00 | 25 | 30 | 5 |
| 2103-11-10 00:00:00 | 2103-11-14 00:00:00 | 8 | 10 | 2 |
| 2103-11-20 00:00:00 | 2103-11-25 00:00:00 | 18 | 25 | 7 |
| 2103-11-14 00:00:00 | 2103-11-20 00:00:00 | 10 | 18 | 8 |
| 2103-11-01 00:00:00 | 2103-11-10 00:00:00 | 5 | 8 | 3 |
+---------------------+---------------------+-------+------+--------+
5 rows in set (0.00 sec)