MySQL adding value from previous row - mysql

I have a table with a single column. The column is like this:
1
2
3
4
5
...
I want to create a query that will display another column that will have the previous value added to it. So:
1 1 ( 0 + 1 )
2 3 ( 1 + 2 )
3 5 ( 2 + 3 )
4 7 ( 3 + 4 )
5 9 ( 4 + 5 )
9 14 (5 + 9)
45 54 ( 9 + 45)
How would I construct a query to accomplish that?
Essentially, I just want the difference between ROW[X], and ROW[X-1].

SELECT a.val, (#runtot := a.val + #runtot) AS rt, ( #runtot := a.val ) ne
FROM Table1 a,(SELECT #runtot:=0) c
This seems to be working. I tried reinit the variable at each stage.
Try it out.
SQLFiddle Demo

TRY
SELECT a.int, (#runtot := a.int + a.int - 1) AS rt
FROM test a,(SELECT #runtot:=0) c
ie
1 1 ( 0 + 1 )
2 3 ( 1 + 2 )
3 5 ( 2 + 3 )
4 7 ( 3 + 4 )
5 9 ( 4 + 5 )
this will result the output you shown

Related

Running total of every increment

I have a table events as follows:
f_id leg
1 1
2 1
3 1
4 2
5 2
6 3
7 1
8 1
9 2
I want a running total of every time the leg changes. Expected output:
f_id leg total_legs
1 1 1
2 1 1
3 1 1
4 2 2
5 2 2
6 3 3
7 1 4
8 1 4
9 2 5
Not sure how to go about this.
SELECT *, #leg_var:=IF(#current_leg=leg, leg) as total_legs FROM `events`
This is clearly wrong.
WITH cte AS ( SELECT *, CASE WHEN LAG(leg) OVER (ORDER BY f_id) = leg
THEN 0
ELSE 1
END lag_leg
FROM test )
SELECT f_id, leg, SUM(lag_leg) OVER (ORDER BY f_id) total_legs
FROM cte;
fiddle
This is a kind of gaps-and-islands problem. In MySQL 8.0, you can use lag() and a cumulative sum():
select fid, leg, sum(not leg <=> lag_leg) over(order by f_id) total_legs
from (
select e.*, lag(leg) over(order by f_id) lag_leg
from events e
) e
The problem can be solved without window functions using variables:
SET #leg_var:=null;
SET #total:=0;
SELECT
f_id,
#leg_var prev_leg,
#total:=#total+if(#leg_var is null or #leg_var<>leg, 1, 0) as total,
#leg_var:=leg as leg
FROM events
ORDER BY f_id;
fiddle here

MySQL: Select top 5 rows based on ID and find Subtotal

Need to select top 5 rows for each id based on desc values of a particular column , value and find the subtotal of that column . for e.g (Tried creating the situation , actual table structure is large )
ID VALUE
1 2
1 3
1 4
1 5
1 6
1 7
1 8
2 9
2 10
2 11
2 12
2 13
2 14
Output Expected
ID VALUE
1 8
1 7
1 6
1 5
1 4
TOTAL 30
2 14
2 13
2 12
2 11
2 10
TOTAL 60
I could select top 5 rows using a code like this ;
#cust_rank := IF(#current_cust = id, #cust_rank + 1, 1) AS cust_rank,
#current_cust := id
and then selecting top 5
Also ,I could subtotal using code like this ;
SELECT id, value FROM source
UNION
SELECT NULL,SUM(value) FROM source
GROUP BY id ORDER BY id;
I need to merge both requirements .
SELECT CAST(id as CHAR(50)) Id, value
FROM (SELECT id , value ,
IF(#lastid=(#lastid:=id), #auto:=#auto+1, #auto:=1) indx
FROM source, (SELECT #lastid:=0, #auto:=1) A
ORDER BY id,value desc)as A
WHERE indx <= 5
Output
Id value
1 8
1 7
1 6
1 5
1 4
2 14
2 13
2 12
2 11
2 10
2nd Query
SELECT 'Total', SUM(value)
FROM (SELECT id , value ,
IF(#lastid=(#lastid:=id), #auto:=#auto+1, #auto:=1) indx
FROM source, (SELECT #lastid:=0, #auto:=1) A
ORDER BY value desc)as A
WHERE indx <= 5
GROUP BY id ;
Output
Total SUM(value)
Total 30
Total 60
Merged Query:
Select
CASE
WHEN indx =6 THEN "Total"
ELSE id
END as ID,value
from
(
select id,value,
IF(#lastid=(#lastid:=id), #auto:=#auto+1, #auto:=1) indx
FROM
(
SELECT CAST(id as CHAR(50)) Id, value
FROM (SELECT id , value ,
IF(#lastid=(#lastid:=id), #auto:=#auto+1, #auto:=1) indx
FROM source, (SELECT #lastid:=0, #auto:=1) A
ORDER BY id,value desc)as A
WHERE indx <= 5
UNION
SELECT CAST(id as CHAR(50))as id, SUM(value)as value
FROM (SELECT id , value ,
IF(#lastid1=(#lastid1:=id), #auto1:=#auto1+1, #auto1:=1) indx
FROM source, (SELECT #lastid1:=0, #auto1:=1) A
ORDER BY value desc)as A
WHERE indx <= 5
GROUP BY id)as output ,(SELECT #lastid:=0, #auto:=1) A ORDER BY id) as output1
Output
ID value
1 8
1 7
1 6
1 5
1 4
Total 30
2 10
2 11
2 12
2 13
2 14
Total 60

Create a Cumulative Sum Column in MySQL Based On an ID

I have a "simplified" table that looks like this:
player round point
1 1 25
2 1 18
3 1 15
1 2 18
2 2 25
3 2 15
I wanna create a view that calculates pointTot cumulatively based upon plrID
plrID rndID pnt [pointTot]
1 1 25 25
2 1 18 18
3 1 15 15
1 2 18 43
2 2 25 43
3 2 15 30
I've been playing around with different methods for the last few hours.
I would need a variable var based upon the plrID
This is as far as I got without being able to work out how to create a
#psum[#plrID]
set #psum := 0;
select `plrID`, `rndID`, `pnt`, (#psum := #psum + `pnt`) as `pointTot`
from `table`
order by `plrID`;
You can do this using below query
select t.plrID,t.rndID,t.pnt,sum(t1.pnt)
from table t
join table t1
on t.plrID = t1.plrID
and t1.rndID<=t.rndID
group by plrID,rndID
You can do this as:
select `plrID`, `rndID`, `pnt`,
(#psum := if(#p = plrId, #psum + pnt,
if(#p := plrId, pnt, pnt)
)
) as pointTot
from `table` cross join
(select #psum := 0, #p := -1) param
order by `plrID`, rndID;
You cannot add this as a view, because variables are not allowed in a view. You can use this version:
select `plrID`, `rndID`, `pnt`,
(select sum(t2.pnt)
from `table` t2
where t2.plrId = t.plrId and t2.rndId <= t.rndId
) as pointTot
from `table` t ;

MySQL complex ranking query

I need to rank users in MySQL where the rank takes into account both ties and continues to counts the tied users as part of the rank.. For example..
points rank
100 1
100 1
100 1
70 4
70 4
60 5
50 6
40 7
40 7
10 8
0 9
0 9
Using the code below I'm ranking as follows...
points rank game
100 1 1
100 1 1
100 1 1
70 2 1
70 2 1
60 3 1
50 4 1
40 5 1
40 5 1
10 6 1
0 7 1
0 7 1
UPDATE rank_table
JOIN (SELECT f.points ,
IF (#lastPoint <> f.points,
#curRank := #curRank +1,
#curRank) AS rank,
#lastPoint := f.points
FROM rank_table f
JOIN (SELECT #curRank := 0, #lastPoint := -1) r
WHERE f.game =1
ORDER BY f.points DESC
) ranks ON (ranks.points = rank_table.points)
SET rank_table.rank = ranks.rank WHERE rank_table.game =1;
Would anyone know it this is possible..?
You do not need any mysql-variable.
Your new rank is the number of players having more points than you.
update
result
join (
select
n.id, count(distinct q.id) total
from result n
left join result q
on
q.points > n.points
group by n.id) m
on
m.id = id
set rank=m.total + 1
(assuming there is some kind of id like player_id)

How to make a fake column with an autoincrement number in a "group by" query

I have data in a table like this:
fgid qty ntid
1 100 10
2 90 10
6 200 11
1 80 11
1 120 12
6 100 12
6 30 13
And i make query :
SELECT fgid, SUM(qty) AS total_qty, COUNT(ntid) AS nt_count FROM sofg
GROUP BY fgid
AND the result is :
fgid total_qty nt_count
1 300 3
2 90 1
6 330 3
Then i want to make the result like this :
no fgid total_qty nt_count
1 1 300 3
2 2 90 1
3 6 330 3
How to do that with a query? where 'no' is (like) autoincrement number.
Try this query.
SELECT
#rownum := #rownum + 1 rownum,
t.*
FROM (SELECT #rownum:=0) r,
(
SELECT fgid, SUM(qty) AS total_qty, COUNT(ntid) AS nt_count FROM sofg GROUP BY fgid
) t;
Basically the same as Dhinakaran's answer, but there's no need to put the whole main query into a subquery. There's no difference to his answer appart from maybe being more pleasing to the eye, but please accept Dhinakaran's answer, as he was faster.
SELECT
#rownum:=#rownum + 1 as rownumber,
fgid,
SUM(qty) AS total_qty,
COUNT(ntid) AS nt_count
FROM sofg
, (select #rownum:=0) v
GROUP BY fgid