How to get difference of two rows in same column - mysql

I have to find the difference in the value of a single column of table as current row value-previous row value for some 'n' number of rows in one column and also I don't have ID to use as reference for increment
date: box_count : total_no_of_boxes_used
1/12/12 2 2
2/12/12 8 6
3/12/12 14 6
I have box_count column and I am trying to get total_no_of_boxes_used column.
Please help me.
Thanks in advance

Given your records are sequential by date.....
SQLFIDDLE DEMO
Query:
select a.date, a.bc, case when (a.bc-b.bc) is null then a.bc else a.bc-b.bc end tot
from tt a
left join
tt b
on a.date > b.date
group by b.date
;
Results:
DATE BC TOT
December, 01 2012 00:00:00+0000 2 2
December, 02 2012 00:00:00+0000 8 6
December, 03 2012 00:00:00+0000 14 6
December, 04 2012 00:00:00+0000 23 9

One way to do this, is using a correlated subquery like so:
SELECT
t1.`date`,
t1.box_count,
t1.box_count -
IFNULL((SELECT t2.box_count
FROM table1 t2
WHERE t2.`date` < t1.`date`
ORDER BY t2.`date` DESC
LIMIT 1),
0 ) AS total_no_of_boxes_used
FROM table1 t1;
SQL Fiddle Demo
This will give you:
| DATE | BOX_COUNT | TOTAL_NO_OF_BOXES_USED |
------------------------------------------------------------------------
| January, 12 2012 00:00:00+0000 | 2 | 2 |
| February, 12 2012 00:00:00+0000 | 8 | 6 |
| March, 12 2012 00:00:00+0000 | 14 | 6 |

Try this:
SELECT date,
(box_count - #diff) total_no_of_boxes_used,
(#diff:=box_count) box_count
FROM table1, (SELECT #diff:=0) A;
Check this SQL FIDDLE DEMO
OUTPUT
| DATE | TOTAL_NO_OF_BOXES_USED | BOX_COUNT |
------------------------------------------------------------------------
| January, 12 2012 00:00:00+0000 | 2 | 2 |
| February, 12 2012 00:00:00+0000 | 6 | 8 |
| March, 12 2012 00:00:00+0000 | 6 | 14 |

Related

I need a query to geta output like pivot table? [duplicate]

This question already has answers here:
How can I return pivot table output in MySQL?
(10 answers)
Closed 2 years ago.
My table look like this
name value monthyear year
g1 10 March 18 2018
g1 11 March 18 2018
g1 34 March 19 2019
g1 45 March 19 2019
g2 10 April 18 2018
g1 11 May 18 2018
g1 34 May 19 2019
g1 45 June 19 2019
And I need out put like this
Name March 18 March 19 April 18 May 18 May 19 June 19
g1 21 79 11 34 45
g2 10
In Pivot table I am getting this, How can I get this table with sql query ? Please help & Thanks in advance.
You can use case expression inside sum. here is the demo.
select
name,
sum(case when monthyear = 'March 18' then value end) as March18
sum(case when monthyear = 'March 19' then value end) as March19
..
..
from yourTable
group by
name
output:
| name | March_18 | March_19 | April_18 | May_18 | May_19 | June_19 |
| ---- | -------- | -------- | -------- | ------ | ------ | ------- |
| g1 | 21 | 79 | | 11 | 34 | |
| g2 | | | 10 | | | |

How to write an SQL query to calculate the average for three consecutive values?

I have a table like this
userID time NoOfVisits
1 2014 50
2 2015 60
3 2016 70
4 2017 80
5 2018 90
6 2019 100
I need to write a sql query which will print time and average of past 3 years NoOfVisits for a particular site.
output should be as
userID time NoOfVisits
1 2014 50.0000
2 2015 55.0000
3 2016 60.0000
4 2017 70.0000
5 2018 80.0000
6 2019 90.0000
Explanation :
For user Id 6 (80+90+100)/3=90.0000
Please help me to solve this problem.
You can use a cumulative average, available in MySQL 8+:
select t.*,
avg(visits) over (order by time rows between 2 preceding and current row) as avg_visits_3
from t;
Assuming there are no gaps between the years (like your sample data), you can self join the table and group by userid, time to get the average:
select
t.userid, t.time, avg(tt.noofvisits) NoOfVisits
from tablename t inner join tablename tt
on tt.time between t.time - 2 and t.time
group by t.userid, t.time
See the demo.
Results:
| userid | time | NoOfVisits |
| ------ | ---- | ---------- |
| 1 | 2014 | 50 |
| 2 | 2015 | 55 |
| 3 | 2016 | 60 |
| 4 | 2017 | 70 |
| 5 | 2018 | 80 |
| 6 | 2019 | 90 |

MySQL `SUM` with `GROUP BY` is missing data in results

I have a database with a table containing information on some images, each row containing a createdAt date and a viewCount. The data ranges from September 2014 until today (July 2016). I want to get a monthly sum of the amount of views across all images for the month
When I run the query
SELECT YEAR(createdAt), MONTH(createdAt), SUM(viewCount)
FROM Images
GROUP BY MONTH(createdAt);
I'm only returned 12 rows with results between September 2014 and August 2015
Year | Month | Views
-------------------
2014 | 9 | 1452
2014 | 10 | 279
2014 | 11 | 34428
2014 | 12 | 4763
2015 | 1 | 2826
2015 | 2 | 777
2015 | 3 | 568
2015 | 4 | 1309
2015 | 5 | 46744
2015 | 6 | 1541
2015 | 7 | 8160
2015 | 8 | 91
If I add a date restraint it will give me the latest data, but again only 12 rows
SELECT YEAR(createdAt), MONTH(createdAt), SUM(viewCount)
FROM Images WHERE createdAt > DATE('2015-08-01 00:00:00')
GROUP BY MONTH(createdAt);
Year | Month | Views
--------------------
2015 | 8 | 981
2015 | 9 | 1031
2015 | 10 | 2566
2015 | 11 | 3325
2015 | 12 | 411
2016 | 1 | 2140
2016 | 2 | 710
2016 | 3 | 714
2016 | 4 | 1985
2016 | 5 | 426
2016 | 6 | 119
2016 | 7 | 81
I do realise that since it's July the second query stops there as that's where the data ends, but why does the first query not return all the results?
Group by year/month:
SELECT YEAR(createdAt), MONTH(createdAt), SUM(viewCount)
FROM Images
--WHERE createdAt > DATE('2015-08-01 00:00:00')
GROUP BY YEAR(createdAt), MONTH(createdAt);
Related Group by clause in mySQL and postgreSQL, why the error in postgreSQL?
Keep in mind that from MySQL 5.7.6+ your initial query may not even work because of only_full_group_by which is set by default.
You can simply add Year to you group by
SELECT YEAR(createdAt), MONTH(createdAt), SUM(viewCount)
FROM Images
GROUP BY YEAR(createdAt), MONTH(createdAt)
ORDER BY YEAR(createdAt), MONTH(createdAt)

how to to get a record from mysql 20 consecutive days?

I have a table XX. i need to get the records which are 20 days consecutive gap .below is my table look
ID ISmen Date
1 0 2013-05-2
2 0 2013-05-2
3 0 2014-04-2
4 1 2014-05-2
5 1 2014-05-2
6 0 2014-05-2
7 0 2014-05-2
8 0 2014-05-2
9 1 2014-05-25
10 1 2014-05-25
11 0 2014-05-26
12 1 2014-05-27
13 0 2014-05-28
From the above table i need to get the records which are ismen is 1 and the next record ismen is also 1 (i.e 4,5 and 9,10 but not 12).and one more thing 4,5 and 9,10 should have 20 days gap
i am getting the records which are 4,5 and 9,10 ..but i can't able to check date difference between the records .i know we can achieve in the loop but i am trying to get in MySQL is it possible or not.I try below query.thanks in advance for help
SELECT *
FROM XX t1,
XX t2
WHERE (t1.ID=t2.ID+1
OR t1.ID=t2.ID-1)
AND t1.Ismen=1
AND t2.Ismen=1
There is a 23 day gap between |4|5| to |9|10| but ignoring the sample data precision, this result:
| ISMEN | T1ID | T2ID | T1DATE | T2DATE |
|-------|------|------|----------------------------|----------------------------|
| 1 | 4 | 9 | May, 02 2014 00:00:00+0000 | May, 25 2014 00:00:00+0000 |
| 1 | 5 | 9 | May, 02 2014 00:00:00+0000 | May, 25 2014 00:00:00+0000 |
| 1 | 4 | 10 | May, 02 2014 00:00:00+0000 | May, 25 2014 00:00:00+0000 |
| 1 | 5 | 10 | May, 02 2014 00:00:00+0000 | May, 25 2014 00:00:00+0000 |
was produced by this query:
select
t1.ismen
, t1.id as t1id
, t2.id as t2id
, t1.`date` as t1date
, t2.`date` as t2date
from table1 as t1
inner join table1 as t2 on t1.ismen = t2.ismen
and t1.`date` + INTERVAL 23 DAY = t2.`date`
The wanted gap between records can be defined in the join conditions (change to 20 or whatever). But do note there is nothing to stop 4 relating to 9 and 10 or 5 to 9 & 10 so you get 4 records in total.
see: http://sqlfiddle.com/#!9/8d941/1
You could reduce that result by some means (e.g. using row_number() but I don't know if that is required.

Select highest 3 scores in each day for every user

I have a MYSQL table like this:
id | userid | score | datestamp |
-----------------------------------------------------
1 | 1 | 5 | 2012-12-06 03:55:16
2 | 2 | 0,5 | 2012-12-06 04:25:21
3 | 1 | 7 | 2012-12-06 04:35:33
4 | 3 | 12 | 2012-12-06 04:55:45
5 | 2 | 22 | 2012-12-06 05:25:11
6 | 1 | 16,5 | 2012-12-06 05:55:21
7 | 1 | 19 | 2012-12-06 13:55:16
8 | 2 | 8,5 | 2012-12-07 06:27:16
9 | 2 | 7,5 | 2012-12-07 08:33:16
10 | 1 | 10 | 2012-12-07 09:25:19
11 | 1 | 6,5 | 2012-12-07 13:33:16
12 | 3 | 6 | 2012-12-07 15:45:44
13 | 2 | 4 | 2012-12-07 16:05:16
14 | 2 | 34 | 2012-12-07 18:33:55
15 | 2 | 22 | 2012-12-07 18:42:11
I would like to display user scores like this:
if a user on a certain day has more than 3 scores it would get only highest 3, repeat that for every day for this user and then add all days together. I want to display this sum for every user.
EDIT:
So in the example above for user 1 on 06.12. I would add top 3 scores together and ignore 4th score, then add to that number top 3 from the next day and so on. I need that number for every user.
EDIT 2:
Expected output is:
userid | score
--------------------
1 | 59 //19 + 16.5 + 7 (06.12.) + 10 + 6.5 (07.12.)
2 | 87 //22 + 0.5 (06.12.) + 34 + 22 + 8.5 (07.12.)
3 | 18 //12 (06.12.) + 6 (07.12.)
I hope this is more clear :)
I would really appreciate the help because I am stuck.
Please take a look at the following code, if your answer to my comment is yes :) Since your data all in 2012, and month of november, I took day.
SQLFIDDLE sample
Query:
select y.id, y.userid, y.score, y.datestamp
from (select id, userid, score, datestamp
from scores
group by day(datestamp)) as y
where (select count(*)
from (select id, userid, score, datestamp
from scores group by day(datestamp)) as x
where y.score >= x.score
and y.userid = x.userid
) =1 -- Top 3rd, 2nd, 1st
order by y.score desc
;
Results:
ID USERID SCORE DATESTAMP
8 2 8.5 December, 07 2012 00:00:00+0000
20 3 6 December, 08 2012 00:00:00+0000
1 1 5 December, 06 2012 00:00:00+0000
Based on your latter updates to question.
If you need some per user by year/month/day and then find highest, you may simply add aggregation function like sum to the above query. I am reapeating myself, since your sample data is for just one year, there's no point group by year or month. That's why I took day.
select y.id, y.userid, y.score, y.datestamp
from (select id, userid, sum(score) as score,
datestamp
from scores
group by userid, day(datestamp)) as y
where (select count(*)
from (select id, userid, sum(score) as score
, datestamp
from scores
group by userid, day(datestamp)) as x
where y.score >= x.score
and y.userid = x.userid
) =1 -- Top 3rd, 2nd, 1st
order by y.score desc
;
Results based on sum:
ID USERID SCORE DATESTAMP
1 1 47.5 December, 06 2012 00:00:00+0000
8 2 16 December, 07 2012 00:00:00+0000
20 3 6 December, 08 2012 00:00:00+0000
UPDATED WITH NEW SOURCE DATA SAMPLE
Simon, please take a look at my own sample. As your data was changing, I used mine.
Here is the reference. I have used pure ansi style without any over partition or dense_rank.
Also note the data I used are getting top 2 not top 3 scores. You can change is accordingly.
Guess what, the answer is 10 times simpler than the first impression your first data gave....
SQLFIDDLE
Query to 1:
-- for top 2 sum by user by each day
SELECT userid, sum(Score), datestamp
FROM scores t1
where 2 >=
(SELECT count(*)
from scores t2
where t1.score <= t2.score
and t1.userid = t2.userid
and day(t1.datestamp) = day(t2.datestamp)
order by t2.score desc)
group by userid, datestamp
;
Results for query 1:
USERID SUM(SCORE) DATESTAMP
1 70 December, 06 2012 00:00:00+0000
1 30 December, 07 2012 00:00:00+0000
2 22 December, 06 2012 00:00:00+0000
2 25 December, 07 2012 00:00:00+0000
3 30 December, 06 2012 00:00:00+0000
3 30 December, 07 2012 00:00:00+0000
Final Query:
-- for all two days top 2 sum by user
SELECT userid, sum(Score)
FROM scores t1
where 2 >=
(SELECT count(*)
from scores t2
where t1.score <= t2.score
and t1.userid = t2.userid
and day(t1.datestamp) = day(t2.datestamp)
order by t2.score desc)
group by userid
;
Final Results:
USERID SUM(SCORE)
1 100
2 47
3 60
Here goes a snapshot of direct calculations of data I used.
SELECT
*
FROM
table1
LEFT JOIN
(SELECT * FROM table1 ORDER BY score LIMIT 3) as lr on DATE(lr.datestamp) = DATE(table1.datastamp)
GROUP BY
datestamp