I'm trying to solve this problem on Hacker Rank:
Input (Projects table)
Output:
2015-10-28 2015-10-29
2015-10-30 2015-10-31
2015-10-13 2015-10-15
2015-10-01 2015-10-04
So what the problem is asking for is to treat consecutive end dates as part of one project and return the start and end dates of projects ordered by the date differences in ascending order. As you can see from the above example, tasks 1,2,3 are the in the same project, tasks 4,5 are in the same project and tasks 7 and 8 are their own projects.
This is one of the solutions I found:
set #sdate = null;
set #nextdate = null;
select sd, max(ed) ed2
from (
select if(#nextdate = start_date, #sdate, #sdate := start_date) as sd,
#nextdate := end_date as ed
from Projects
order by start_date
) tmp
group by sd
order by datediff(max(ed), sd)
It is using variables to store the previous end date and compare it to the current row, but I'm confused by the order by clause in the subquery:
If I take out the 'order by start_date' in the subquery, the result it returns will be wrong -- I was under the impression that in MySQL the ordering of subqueries is ignored?
My understanding was that order by is executed after the select so here it would be ordering the results from select in the subquery, but it seems like it's actually ordering the source table (Properties) before the select statement -- am I correct?
Could someone help me understand why this is the case? Thanks
The ORDER BY in the subquery is necessary for the variable assignment to work. This is similar to the idea of assigning row numbers in older MySQL version. When you run:
SELECT *
FROM Projects;
Without the ORDER BY, you'll get almost every Start_date value in ascending order except for the Start_date of 2015-11-04 until 2015-11-07 which gives you result in this order:
...
ID Start_date End_date
16 2015-11-04 2015-11-05
10 2015-11-07 2015-11-08
15 2015-11-06 2015-11-07
11 2015-11-05 2015-11-06
...
It start from 4 but then the next one is 7,6 then 5. This breaks the variable assignment. If you run the query like this:
SELECT *,IF(#nextdate = start_date, #sdate, #sdate := start_date) AS sd,
#nextdate := end_date AS ed
FROM Projects;
You can see the difference in the results where the Start_date is in the correct order vs with the incorrect order:
+-----+------------+------------+------------+------------+
| ID | Start_date | End_date | sd | ed |
+-----+------------+------------+------------+------------+
| 1 | 2015-10-01 | 2015-10-02 | 2015-10-01 | 2015-10-02 |
| 24 | 2015-10-02 | 2015-10-03 | 2015-10-01 | 2015-10-03 |
| 2 | 2015-10-03 | 2015-10-04 | 2015-10-01 | 2015-10-04 |
| 23 | 2015-10-04 | 2015-10-05 | 2015-10-01 | 2015-10-05 |
.......
| 3 | 2015-10-11 | 2015-10-12 | 2015-10-11 | 2015-10-12 |
| 22 | 2015-10-12 | 2015-10-13 | 2015-10-11 | 2015-10-13 |
.......
| 16 | 2015-11-04 | 2015-11-05 | 2015-11-04 | 2015-11-05 |
| 10 | 2015-11-07 | 2015-11-08 | 2015-11-07 | 2015-11-08 |
| 15 | 2015-11-06 | 2015-11-07 | 2015-11-06 | 2015-11-07 |
| 11 | 2015-11-05 | 2015-11-06 | 2015-11-05 | 2015-11-06 |
+-----+------------+------------+------------+------------+
With the subquery returning the result like above, whereby 3 of the rows should actually generate sd=2015-11-04 but instead have different value, the outer query GROUP BY will then gave 14 rows of results. By adding the ORDER BY Start_date in the subquery, you'll get the result for 2015-11-04 until 2015-11-07 like this instead:
+----+------------+------------+------------+------------+
| ID | Start_date | End_date | sd | ed |
+----+------------+------------+------------+------------+
| 16 | 2015-11-04 | 2015-11-05 | 2015-11-04 | 2015-11-05 |
| 11 | 2015-11-05 | 2015-11-06 | 2015-11-04 | 2015-11-06 |
| 15 | 2015-11-06 | 2015-11-07 | 2015-11-04 | 2015-11-07 |
| 10 | 2015-11-07 | 2015-11-08 | 2015-11-04 | 2015-11-08 |
+----+------------+------------+------------+------------+
So, it's not actually the ordering that makes the answer wrong but it's the extra rows in the end result.
Here's a fiddle to play around
Related
How can I find ALL occurrences of two datetimes that are close to each other for the same member (among other criteria). That is I have a table with a bunch of date times, and I'm looking to find any instances of two which are close together in time for the same member ID. Output would just be those two times that are close together, and the member ID.
Usually would provide some example, but have no idea how to approach this.
Database looks like:
+-----------+---------------------+
| MemberID | datetime |
+-----------+---------------------+
| John | 2019-10-10 01:01:01 |
| John | 2020-08-10 01:01:01 |
| John | 2020-08-10 04:01:01 |
| John | 2020-09-07 01:01:01 |
| Joe | 2019-10-10 01:01:01 |
| Joe | 2020-10-10 01:01:01 |
| Rich | 2018-10-10 01:01:01 |
| Rich | 2019-10-10 01:01:01 |
| Rich | 2020-02-10 09:01:01 |
| Rich | 2020-02-10 10:11:01 |
+-----------+---------------------+
Output would be (Only those rows which were close in time [within 6 hours of each other] for that MemberID
+-----------+---------------------+
| MemberID | datetime |
+-----------+---------------------+
| John | 2020-08-10 01:01:01 |
| John | 2020-08-10 04:01:01 |
| Rich | 2020-02-10 09:01:01 |
| Rich | 2020-02-10 10:11:01 |
+-----------+---------------------+
Update: Cannot us lead or lag, mysql version is 5.X
You can use lag():
select t.*
from (select t.*,
lag(dt) over (partition by member order by dt) as prev_dt
from t
) t
where prev_dt > dt - interval 6 hour;
This requires MySQL 8+. In earlier versions, you can use a correlated subquery:
select t.*
from (select t.*,
(select max(t2.dt)
from t t2
where t2.member = t.member and
t2.dt < t.dt
) as prev_dt
from t
) t
where prev_dt > dt - interval 6 hour;
I have a table in an old version of MySQL 5.x like this:
+---------+------------+------------+
| Task_ID | Start_Date | End_Date |
+---------+------------+------------+
| 1 | 2015-10-15 | 2015-10-16 |
| 2 | 2015-10-17 | 2015-10-18 |
| 3 | 2015-10-19 | 2015-10-20 |
| 4 | 2015-10-21 | 2015-10-22 |
| 5 | 2015-11-01 | 2015-11-02 |
| 6 | 2015-11-17 | 2015-11-18 |
| 7 | 2015-10-11 | 2015-10-12 |
| 8 | 2015-10-12 | 2015-10-13 |
| 9 | 2015-11-11 | 2015-11-12 |
| 10 | 2015-11-12 | 2015-11-13 |
| 11 | 2015-10-01 | 2015-10-02 |
| 12 | 2015-10-02 | 2015-10-03 |
| 13 | 2015-10-03 | 2015-10-04 |
| 14 | 2015-10-04 | 2015-10-05 |
| 15 | 2015-11-04 | 2015-11-05 |
| 16 | 2015-11-05 | 2015-11-06 |
| 17 | 2015-11-06 | 2015-11-07 |
| 18 | 2015-11-07 | 2015-11-08 |
| 19 | 2015-10-25 | 2015-10-26 |
| 20 | 2015-10-26 | 2015-10-27 |
| 21 | 2015-10-27 | 2015-10-28 |
| 22 | 2015-10-28 | 2015-10-29 |
| 23 | 2015-10-29 | 2015-10-30 |
| 24 | 2015-10-30 | 2015-10-31 |
+---------+------------+------------+
If the End_Date of the tasks are consecutive,
then they are part of the same project.
I am interested in finding the total number of different projects completed.
If there is more than one project that have the same number of completion days,
then order by the Start_Date of the project.
For this few sample records the expected output would be:
2015-10-15 2015-10-16
2015-10-17 2015-10-18
2015-10-19 2015-10-20
2015-10-21 2015-10-22
2015-11-01 2015-11-02
2015-11-17 2015-11-18
2015-10-11 2015-10-13
2015-11-11 2015-11-13
2015-10-01 2015-10-05
2015-11-04 2015-11-08
2015-10-25 2015-10-31
I am a bit jammed with this.
I would really appreciate any help. Thanks.
Following query should work:
select tmp.projectid, date_sub(max(tmp.ed2), interval max(tmp.projectdays) day) start_date,
max(tmp.ed2) end_date,
max(tmp.projectdays) No_Of_ProjectDays
from
(
select t1.task_id tid1, t1.start_date sd1, t1.end_date ed1,
t2.task_id tid2, t2.start_date sd2, t2.end_date ed2,
case when datediff(t2.start_date, ifnull(t1.start_date,'1000-01-01')) != 1
then (#pid := #pid + 1)
else (#pid := #pid)
end as ProjectId,
case when datediff(t2.start_date, ifnull(t1.start_date,'1000-01-01')) != 1
then (#pdays := 1)
else (#pdays := #pdays + 1)
end as ProjectDays
from tasks t1 right join tasks t2
on t2.task_id = t1.task_id + 1
cross join (select #pid :=1, #pdays := 1) vars
) tmp
group by tmp.projectid
order by max(tmp.projectdays), start_date
Please find the Demo here.
EDIT : I have made changes in the query and link according to new data sample. Please have a look.
This answers -- and answers correctly -- the original version of this question.
Hmmmm . . . I think you can use variables. The simplest way is to generate a sequential number and then subtract this value to get a constant for adjacent rows from the date:
select min(start_date), max(end_date)
from (select t.*, (#rn := #rn + 1) as rn
from (select t.* from tasks t order by end_date) t cross join
(select #rn := 0) params
) t
group by (end_date - interval rn day);
Here is a db<>fiddle.
It's a little tricky problem, but the query below works fine.
It builds two tables, one with Start_Date and other with End_Date
that NOT IN End_Date and Start_Date respectively from Projects table,
and query these tables fetching Start_Date WHERE Start_Date < End_Date grouping by Start_Date
using aggregate function MIN with End_Date to get a complete Project.
DATEDIFF(MIN(End_Date), Start_Date) to calculate project_duration and able to order by project_duration.
SELECT Start_Date, MIN(End_Date) AS End_Date, DATEDIFF(MIN(End_Date), Start_Date) AS project_duration
FROM
(SELECT Start_Date FROM Projects WHERE Start_Date NOT IN (SELECT End_Date FROM Projects)) a,
(SELECT End_Date FROM Projects WHERE End_Date NOT IN (SELECT Start_Date FROM Projects)) b
WHERE Start_Date < End_Date
GROUP BY Start_Date
ORDER BY project_duration ASC, Start_Date ASC;
expected output
+------------+------------+---------------+
| Start_Date | End_Date | project_duration |
+------------+------------+---------------+
| 2015-10-15 | 2015-10-16 | 1 |
| 2015-10-17 | 2015-10-18 | 1 |
| 2015-10-19 | 2015-10-20 | 1 |
| 2015-10-21 | 2015-10-22 | 1 |
| 2015-11-01 | 2015-11-02 | 1 |
| 2015-11-17 | 2015-11-18 | 1 |
| 2015-10-11 | 2015-10-13 | 2 |
| 2015-11-11 | 2015-11-13 | 2 |
| 2015-10-01 | 2015-10-05 | 4 |
| 2015-11-04 | 2015-11-08 | 4 |
| 2015-10-25 | 2015-10-31 | 6 |
+------------+------------+---------------+
I have two tables, one is called Attendance and the other is called Timeslices, I am trying to get the total seconds of Attendances subtracted from Timeslices for the current week and also with Doctrine.
I've got to get the rows but I have to sum and subtract each of them out of the query, but I need to learn to do it in one query.
This is the structure of the Attendance Table:
SELECT * FROM attendance;
+----+---------+---------------------+--------+---------------------+---------------------+
| id | user_id | day | status | check_in | check_out |
+----+---------+---------------------+--------+---------------------+---------------------+
| 1 | 1 | 2019-12-18 00:00:00 | end | 2019-12-18 09:52:00 | 2019-12-18 23:37:02 |
| 2 | 1 | 2019-12-19 00:00:00 | end | 2019-12-19 12:12:00 | 2019-12-19 21:05:00 |
+----+---------+---------------------+--------+---------------------+---------------------+
Timeslice table:
SELECT * FROM timeslice;
+----+---------------+-------------------------------------+---------------------+---------------------+---------------------+
| id | attendance_id | title | day | start_at | stopped_at |
+----+---------------+-------------------------------------+---------------------+---------------------+---------------------+
| 20 | 1 | Sacar al perro, ducharme y vestirme | 2019-12-18 00:00:00 | 2019-12-18 15:57:50 | 2019-12-18 12:15:36 |
| 21 | 1 | Dormir | 2019-12-18 00:00:00 | 2019-12-18 18:44:30 | 2019-12-18 16:16:44 |
| 22 | 1 | Descansar | 2019-12-18 00:00:00 | 2019-12-18 23:04:53 | 2019-12-18 20:56:29 |
| 23 | 2 | Comer | 2019-12-19 00:00:00 | 2019-12-19 16:03:00 | 2019-12-19 15:37:00 |
| 24 | 2 | Comer | 2019-12-19 00:00:00 | 2019-12-19 16:55:00 | 2019-12-19 16:17:00 |
| 25 | 2 | ducharme | 2019-12-19 00:00:00 | 2019-12-19 19:58:00 | 2019-12-19 17:20:00 |
+----+---------------+-------------------------------------+---------------------+---------------------+---------------------+
This is my current query in which I get the results, but then I have to calculate out of the query to get the desired result and SQLFiddle:
http://sqlfiddle.com/#!9/646be/3
SELECT SUM(TIME_TO_SEC(TIMEDIFF(a.check_out, a.check_in))) AS secondsAttendance
, ( SELECT SUM(TIME_TO_SEC(TIMEDIFF(t.start_at, t.stopped_at)))
FROM timeslice t
WHERE t.attendance_id = a.id
) secondsPauses
FROM attendance a
GROUP
BY a.id
What I need as I said before is to be able to do it in the same query without having to use PHP and with Doctrine
I've changed my answer after your comments. If you only need the value it seams that all you need to do is to use you initial query (with a few twicks) as a
subquery in the FROM clause (Derived Table) and then, do your calculations over it. In this case simply need to SUM the result of subtracting the secondsPauses to the secondsAttendance, like this:
-- make the calculation you need over the results
SELECT SUM(Results.secondsAttendance - Results.secondsPauses) as ActualValue
FROM (
-- use you initial results as a subquery and name it as Results
SELECT
SUM(TIME_TO_SEC(TIMEDIFF(a.check_out, a.check_in))) AS secondsAttendance,
(SELECT SUM(TIME_TO_SEC(TIMEDIFF(t.start_at, t.stopped_at)))
FROM timeslice t WHERE t.attendance_id = a.id) AS secondsPauses
FROM attendance a
-- filter date for the current week
where yearweek(DATE(a.check_in), 1) = yearweek(curdate(), 1)
GROUP BY a.id
) Results;
The result is:
+-------------+
| ActualValue |
+-------------+
| 38258 |
+-------------+
SqlFiddle in here
Let's say I have a table "calendar"
+------------+
| day_date |
+------------+
| 2015-01-01 |
| 2015-01-02 |
| 2015-01-03 |
| .......... |
| 2015-07-14 |
| 2015-07-15 |
+------------+
With this query I can select the WEEK (that I need)
SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS YEAR,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start
FROM calendar
GROUP BY NUM_WEEK
And this is the result:
+----------+------+------------+
| NUM_WEEK | YEAR | date_start |
+----------+------+------------+
| 29 | 2015 | 2015-07-20 |
| 30 | 2015 | 2015-07-27 |
| 31 | 2015 | 2015-08-03 |
| 32 | 2015 | 2015-08-10 |
| 33 | 2015 | 2015-08-17 |
| 34 | 2015 | 2015-08-24 |
| 35 | 2015 | 2015-08-31 |
| 36 | 2015 | 2015-09-07 |
| 37 | 2015 | 2015-09-14 |
| 38 | 2015 | 2015-09-21 |
| 39 | 2015 | 2015-09-28 |
| 40 | 2015 | 2015-10-05 |
| 41 | 2015 | 2015-10-12 |
| 42 | 2015 | 2015-10-19 |
| 43 | 2015 | 2015-10-26 |
+----------+------+------------+
Now I have another table:
+----+------------+--------+---------------------+
| id | id_account | amount | date_transaction |
+----+------------+--------+---------------------+
| 1 | 283 | 150 | 2015-06-21 15:50:47 |
| 2 | 283 | 47.74 | 2015-07-23 15:55:44 |
| 3 | 281 | 21.55 | 2015-08-24 12:27:11 |
| 4 | 283 | 11.22 | 2015-08-25 10:00:54 |
+----+------------+--------+---------------------+
They are gaps in date.
With a similar query:
SELECT WEEK(date_transaction,1) AS NUM_WEEK,
YEAR(date_transaction) AS YEAR,
STR_TO_DATE(CONCAT(YEAR(date_transaction),WEEK(date_transaction,1),' Monday'), '%X%V %W')
AS date_start,
transaction.id_account,
SUM(amount) as total FROM transaction
INNER JOIN account ON account.id_account = transaction.id_account
WHERE amount > 0 AND transaction.id_account
IN ( SELECT id_account FROM account WHERE id_customer = 12 )
GROUP BY id_account, WEEK(date_transaction,1)
I obtain this result (probably data are not accurate, referring to previous tables, just to explain).
+----------+------+------------+-----------+----------+
| NUM_WEEK | YEAR | date_start | idAccount | total |
+----------+------+------------+-----------+----------+
| 29 | 2015 | 2015-07-20 | 281 | 22377.00 |
| 30 | 2015 | 2015-07-27 | 281 | 11550.00 |
| 32 | 2015 | 2015-08-04 | 281 | 4500.00 |
| 30 | 2015 | 2015-07-27 | 283 | 1500 |
+----------+------+------------+-----------+----------+
What I would, RIGHT (or LEFT) JOINING the two tables?
The min (and max) WEEK, so I can... (see 2)
Fill the gaps with missing WEEKS with NULL VALUES.
E.g., in a more complicated resultset:
+----------+------+------------+-----------+----------+
| NUM_WEEK | YEAR | date_start | idAccount | total |
+----------+------+------------+-----------+----------+
| 29 | 2015 | 2015-07-20 | 281 | 22377.00 |
| 30 | 2015 | 2015-07-27 | 281 | 11550.00 |
| 31 | 2015 | 2015-07-02 | 281 | NULL |
| 32 | 2015 | 2015-08-09 | 281 | 4500.00 |
| 29 | 2015 | 2015-08-09 | 283 | NULL |
| 30 | 2015 | 2015-07-16 | 283 | 1500 |
| 31 | 2015 | 2015-07-16 | 283 | NULL |
| 32 | 2015 | 2015-07-16 | 283 | NULL |
+----------+------+------------+-----------+----------+
Note, for example, that id=283 now has NULL at WEEK 29, 31 and 32, for example, like id=281 has NULL in WEEK 31.
I prepared also SQLFiddle here: http://sqlfiddle.com/#!9/a8fdc/3
Thank you very much.
I take a look on your question and i came up with this solution. Here is how your query could look like:
SELECT t1.NUM_WEEK, t1.`YEAR`, t1.date_start, t1.id_account, t2.total
FROM (SELECT c.NUM_WEEK, c.`YEAR`, c.date_start, a.id_account
FROM (SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK) c
INNER JOIN account a
ON FIND_IN_SET(a.id_account, c.accounts_id)
ORDER BY a.id_account, c.NUM_WEEK) t1
LEFT JOIN
(SELECT WEEK(t.date_transaction,1) AS NUM_WEEK,
YEAR(t.date_transaction) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(t.date_transaction),WEEK(t.date_transaction,1),' Monday'), '%X%V %W') AS date_start,
t.id_account, SUM(t.amount) AS total
FROM `transaction` t
INNER JOIN account a
ON a.id_account = t.id_account
WHERE t.amount > 0 AND
t.id_account IN (SELECT id_account FROM account WHERE id_customer = 12)
GROUP BY id_account, WEEK(date_transaction,1)) t2
ON t1.NUM_WEEK = t2.NUM_WEEK AND t1.YEAR = t2.YEAR AND t1.id_account = t2.id_account;
Here is SQL Fiddle for that so you can check up result. Hope that is what are you looking for.
Little explanation:
First think i done is that I little modified your first query where you extract data from table calendar and add there one new column called accounts_id. That query now look's like this:
SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK
Please pay attention on this line in SELECT statement
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
Note that when you select for specific customer you need to change customer ID in this line too!!!
Here is Fiddle so you can check result that this query produce.
This is necessary because we need to connect each week with each account to get desired result.
Next step is to extend previous query so we could separate accounts_id column (look result of previous query) so we could get row for each value in that column. Extended query look like this:
SELECT c.NUM_WEEK, c.`YEAR`, c.date_start, a.id_account
FROM (SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK) c
INNER JOIN account a
ON FIND_IN_SET(a.id_account, c.accounts_id)
ORDER BY a.id_account, c.NUM_WEEK
and output you can see in this Fiddle
After that all we need to do is to make left join between this query and query you already wrote in your question (last query).
There might be a better solution or even this one maybe can be improved a little, but I don't have much time now to deal with that and this is the first think that cross my mind...
GL!
P. S. pay attention when you use reserved word in MySQL like YEAR, TRANSACTION etc for column name (as column_name).. that can cause you a treble if have to use them in name of column or table use backquote () to mark them (asyear`)...
Hi All I have a result from mysql that looks like this:
+---------------------+------+
| timestamp | data |
+---------------------+------+
| 2015-06-01 04:25:18 | 10 |
| 2015-06-15 04:25:18 | 20 |
| 2015-06-30 04:25:18 | 30 |
| 2015-07-01 04:25:18 | 50 |
| 2015-07-15 04:25:18 | 60 |
| 2015-07-30 04:25:18 | 70 |
| 2015-08-01 04:25:18 | 80 |
| 2015-08-15 04:25:18 | 90 |
| 2015-08-30 04:25:18 | 100 |
+---------------------+------+
I can use a query to work out the delta so it is like this:
+---------------------+------+------+
| timestamp | data | delta |
+---------------------+------+------+
| 2015-06-01 04:25:18 | 10 | 0 |
| 2015-06-15 04:25:18 | 20 | 10 |
| 2015-06-30 04:25:18 | 30 | 10 |
| 2015-07-01 04:25:18 | 50 | 20 |
| 2015-07-15 04:25:18 | 60 | 10 |
| 2015-07-30 04:25:18 | 70 | 10 |
| 2015-08-01 04:25:18 | 80 | 10 |
| 2015-08-15 04:25:18 | 90 | 10 |
| 2015-08-30 04:25:18 | 100 | 10 |
+---------------------+------+------+
And what I am after is a grouping of the delta column by month:
+-------+-------------+
| month | consumption |
+-------+-------------+
| 6/15 | 20 |
| 7/15 | 40 |
| 8/15 | 30 |
+-------+-------------+
I thought I had to try GROUP BY MONTH(timestamp) but it does not aggregate the deltas.
Any thoughts?
EDIT
to clarify the delta is a calculated column here is a modified query to show you what i mean:
SELECT
node_time,
node_read - #prev AS delta,
#prev := waveflow_data.node_read
FROM
meter_data
INNER JOIN waveflow_data ON meter_data.node_address = waveflow_data.node_address
CROSS JOIN (SELECT #prev := (SELECT node_read FROM waveflow_data ORDER BY `node_time` DESC LIMIT 1)) variable_initialization_query_alias
WHERE
meter_data.node_address = '10164E998976'
ORDER BY waveflow_data.`node_time` DESC
You just need to sum(delta) like below:
select time_stamp,sum(delta) as Consumption from test
group by month(time_stamp);
Check SQL FIDDLE DEMO
If you want the final result from the initial given set of data then you can do as
select
date_format(timestamp,'%m/%y') as month,
sum(delta) as delta
from
(
select
timestamp,
data,
#diff:= if(#prev=0,0,(data - #prev)) as delta,
#prev:= data
from table_name,(select #prev:=0)x
order by timestamp
)x
group by month;
DEMO
Say if you have a query like, Select timestamp,data,delta from mytable groupby timestamp
update it to Select DATE_FORMAT(timestamp,'%m/%y') as timestamp,data,delta from mytable groupby timestamp
The timestamp would now be in your desired format and grouping would automatically be done based on that.