Next value by previous data - mysql

I am trying to create a query that will query the next result by looking into data as how it previous was.
So my data is like
Train - Station - Time
158 Station1 11:10
158 Station1 11:11
158 Station1 11:12
158 Station1 11:13
158 Station1 11:14
158 Station2 11:25
158 Station2 11:26
158 Station2 11:27
158 Station3 11:41
158 Station3 11:42
158 Station3 11:43
158 Station3 11:44
158 Station3 11:45
158 Station4 11:50
158 Station4 11:51
158 Station4 11:52
158 Station4 11:53
So lets say im at "Station3"
I am using the following query to find out what previous Station is:
SELECT * FROM Train
WHERE Train = '158' AND Station NOT LIKE 'Station3'
ORDER BY Time DESC
LIMIT 1
I want to query what the next Station is, but i cant really figure out to make that query. Any tips?
Edit:
Ok, lets say that my table have more information, about previous train runs, and it is from that i want to check what the next station will be.
Train - Station - Time
158 Station1 10:10
158 Station1 10:11
158 Station1 10:12
158 Station1 10:13
158 Station1 10:14
158 Station2 10:25
158 Station2 10:26
158 Station2 10:27
158 Station3 10:41
158 Station3 10:42
158 Station3 10:43
158 Station3 10:44
158 Station3 10:45
158 Station4 10:50
158 Station4 10:51
158 Station4 10:52
158 Station4 10:53
158 Station5 10:55
158 Station5 10:56
158 Station6 10:57
158 Station6 10:58
158 Station1 11:10
158 Station1 11:11
158 Station1 11:12
158 Station1 11:13
158 Station1 11:14
158 Station2 11:25
158 Station2 11:26
158 Station2 11:27
158 Station3 11:41
158 Station3 11:42
158 Station3 11:43
158 Station3 11:44
158 Station3 11:45
158 Station4 11:50
158 Station4 11:51
158 Station4 11:52
158 Station4 11:53
159 Station1 11:10
159 Station1 11:11
159 Station1 11:12
159 Station1 11:13
159 Station1 11:14
159 Station2 11:25
159 Station2 11:26
159 Station2 11:27
159 Station3 11:41
159 Station3 11:42
159 Station3 11:43
159 Station3 11:44
159 Station3 11:45
159 Station4 11:50
158 Station4 11:51
159 Station4 11:52
159 Station4 11:53
So lets say im at the Train 158 Station4 Time 11:53, and i dont know what the next Station is, and i want to query it is Station5. How would i be doing that?

if you only need to know the next station you could use a subquery for max time for station3 and train 158
select * from
my_table
where time > (
select max(time) max_time
from my_table
where Train = '158' AND Station = 'Station3' )
and train = '158'
order by time limit 1

Other approach with out first finding the MAX(time) for station.
MySQL 8.0+ makes it really eazy with LEAD to get the next records data.
Query
SELECT
Table1.Train
, Table1.next_station AS station
, Table1.next_station_time AS time
FROM (
SELECT
*
, LEAD(Station) OVER (PARTITION BY Train ORDER BY Time) AS next_station
, LEAD(Time) OVER (PARTITION BY Train ORDER BY Time) AS next_station_time
FROM
Table1
WHERE
Train = 158
)
AS Table1
WHERE
Table1.station = 'station3'
AND
Table1.station <> Table1.next_station
see demo https://www.db-fiddle.com/f/9Ld7XznMEuzNdRC3dmysUt/1
In the older MySQL versions we need to be more creative because LEAD isn't supported.
Best way to simulate LEAD is by using MySQL's user variables, and a shifting self LEFT JOIN
Keep in mind MySQL user variables work in MySQL 5.1+
Query
SELECT
current_train AS train
, next_station AS station
, next_time AS time
FROM (
SELECT
t1.Train AS current_train
, t1.Station AS current_station
, t1.Time AS `current_time`
, t2.Train AS next_train
, t2.Station AS next_station
, t2.Time AS next_time
FROM (
SELECT
*
, #rownum1 := #rownum1 + 1 AS rownum
FROM
Table1
CROSS JOIN ( SELECT #rownum1 := 0 ) AS i
WHERE
Train = 158
ORDER BY
Time ASC
) AS t1
LEFT JOIN (
SELECT
*
, #rownum2 := #rownum2 + 1 AS rownum
FROM
Table1
CROSS JOIN ( SELECT #rownum2 := 0 ) AS i
WHERE
Train = 158
ORDER BY
Time ASC
) AS t2
ON
t1.rownum + 1 = t2.rownum
)
AS records
WHERE
records.current_station = 'station3'
AND
records.current_station <> records.next_station
See demo http://sqlfiddle.com/#!9/ff23fc/38

On a simpler way, using self join could help you achieve it.
Try this:
select t1.* from train t1
right join train t2 on t1.train=t2.train
where t1.station != 'Station3' and t1.time>(t2.time)
and t2.station='Station3' limit 1 ;
Try changing the station value on both table t1 and t2 to your desired value which is Station3 in this case.
Live SQL Fiddle demo here.

Related

MYSQL with SUM results and GROUP BY and SUM Again

I have a query that I need to SUM the trid column after summing the raised amount
SELECT
`ppm_campaign_id`.`meta_value` AS `campaign_id`,
`trasnlations`.`trid` AS `trid`,
`ppm_campaign_value`.`meta_value` AS `raised`
FROM (((`thf_posts` `posts`
LEFT JOIN `thf_postmeta` `ppm_campaign_id`
ON (((`ppm_campaign_id`.`meta_key` = 'campaign_id')
AND (`ppm_campaign_id`.`post_id` = `posts`.`ID`))))
LEFT JOIN `thf_postmeta` `ppm_campaign_value`
ON (((`ppm_campaign_value`.`meta_key` = 'campaign_value')
AND (`ppm_campaign_value`.`post_id` = `posts`.`ID`))))
LEFT JOIN `thf_icl_translations` `trasnlations`
ON ((`trasnlations`.`element_id` = `ppm_campaign_id`.`meta_value`)))
WHERE ((`ppm_campaign_id`.`meta_value` IS NOT NULL)
AND (`trasnlations`.`trid` IS NOT NULL))
GROUP BY `ppm_campaign_id`.`meta_value`
Result
campaign_id trid raised
1022 564 4137.5
1031 564 3937.5
1698 653 3010
1700 655 10
1702 657 750
1712 653 3030
1713 655 20
1727 657 20
2163 682 0.9
2164 682 50
2166 683 200
2168 684 50
Now I want the sum of trid combined so summing trid = 682 the result of raised should be 50.9 in both campaign_id
Expected Result
campaign_id trid raised
1022 564 8075
1031 564 8075
1698 653 3010
1700 655 10
1702 657 750
1712 653 3030
1713 655 20
1727 657 20
2163 682 50.9
2164 682 50.9
2166 683 200
2168 684 50
Considering the output of your query is stored in temptable. Please try the below query. Hope it helps.
SELECT t1.campaign_id, t1.trid, t2.raised_sum
FROM temptable t1 JOIN (
SELECT trid, SUM(raised) as raised_sum
FROM temptable GROUP BY trid) t2
ON t1.trid=t2.trid
GROUP BY t1.campaign_id, t1.trid, t2.raised_sum;
If more details on the tables included in your query and sample data can be given, we can try to get the data directly from them.

select top 5 group by and order by

I have a table like this:
CITY QNT EXP RATE
LONDON 60 6 900
LONDON 35 8 337
LONDON 24 6 300
LONDON 22 6 266
BIRMINGHAM 22 6 266
NEWYORK 69 19 263
LONDON 21 6 250
ROME 24 7 242
BIRMINGHAM 24 7 242
BIRMINGHAM 24 7 242
LONDON 20 6 233
BIRMINGHAM 23 7 228
STUTTGART 29 9 222
LONDON 19 6 216
STUTTGART 25 8 212
PARIS 31 10 210
STUTTGART 34 11 209
STUTTGART 34 11 209
BIRMINGHAM 18 6 200
BIRMINGHAM 18 6 200
NEWYORK 18 6 200
BIRMINGHAM 17 6 183
LONDON 19 7 171
MUNICH 16 6 166
PARIS 21 8 162
STUTTGART 39 15 160
BARCELONA 18 7 157
LONDON 18 7 157
ROME 33 13 153
BARCELONA 15 6 150
PARIS 25 10 150
ROME 20 8 150
PARIS 25 10 150
ROME 20 8 150
LONDON 15 6 150
MUNICH 15 6 150
BIRMINGHAM 15 6 150
NEWYORK 15 6 150
LONDON 17 7 142
MUNICH 17 7 142
Here is my sql command:
select CITY, QNT, EXP, (QNT-EXP)*100/EXP as RATE
from tbl_city
order by RATE desc
I want to group by city these results. But I couldn't do it. I want the top5 line to change most.
Result should be like that:
LONDON 60 6 900
BIRMINGHAM 22 6 266
NEWYORK 69 19 263
ROME 24 7 242
STUTTGART 29 9 222
This is from MySQL 5.6.
select CITY, QNT, EXP, (QNT-EXP)*100/EXP as RATE
from tbl_city GROUP BY CITY
order by RATE desc LIMIT 5
Tested in this link: http://www.sqlfiddle.com/#!9/3f1ea1/1
This is from MS SQL Server 2017
select TOP 5 f.CITY, f.QNT, f.EXP, x.RATE
from (
select CITY, MAX((QNT-EXP)*100/EXP) as RATE
from tbl_city GROUP BY CITY
) as x inner join tbl_city as f on f.CITY = x.CITY
and ((f.QNT-f.EXP)*100/f.EXP) = x.RATE
ORDER BY RATE DESC;
Tested in this link: http://www.sqlfiddle.com/#!18/7b8da/61
Maybe you want something like this?
select top 5 CITY, QNT, EXP, RATE
from (
select *, row_number() over (partition by CITY order by RATE desc) AS RN
from (
select CITY, QNT, EXP, (QNT-EXP)*100/EXP as RATE
from tbl_city
) X
) Y
where RN = 1
order by RATE desc
I didn't test this, but it should take first the row for the city with biggest rate, and then take top 5 rows so that that the same city is not duplicated
I don't know what is logic behind the specified formula but this does what you want
select top 5 * from (
select top(1) with ties city, qnt, exp, (qnt-exp)*100/exp as rate
from tbl_city
order by row_number() over (partition by city order by (qnt-exp)*100/exp desc)
)t
order by rate desc
However, top(1) with ties with analytical functions are available in SQL Server.

Finding a running Difference in Columns with mySQL

I am trying to get the following result:
HOUR Throughput Difference
0 298 0
1 209 -89
6 1 -208
7 8 -7
8 9 1
9 175 166
10 223 and so on
11 260
12 246
13 195
14 170
15 230
16 200
17 301
18 316
19 282
20 293
21 281
22 175
23 244
The sql statement i currently have is
SELECT DISTINCT
HOUR(p_datetime) as HOUR,
Count(p_type) as Throughput
FROM
product_log
WHERE
DATE(p_datetime) = '2013-11-30' AND
p_type='STACK'
GROUP BY HOUR;
I have been trying for a while now and cannot find a solution This is done in mysql.
Thanks!
One way to do it
SELECT hour, throughput, difference
FROM
(
SELECT hour, throughput,
throughput - #p difference, #p := throughput
FROM
(
SELECT HOUR(p_datetime) hour,
COUNT(*) throughput
FROM product_log l
WHERE p_datetime >= '2013-11-30'
AND p_datetime < '2013-11-31'
AND p_type = 'stack'
GROUP BY HOUR(p_datetime)
) a CROSS JOIN (SELECT #p := 0) i
) b
Here is SQLFiddle demo

SELECT MIN, MAX, AVG and current (for latest insert ID) value all together

I need to get GROUPed BY values,
but I need to see not a random price value (when I select price), but latest price value (price for a row with highest ID within this GROUP)
SELECT ID, price,
ROUND(AVG(price)),
MIN(price),
MAX(price),
ROUND((AVG(price)-MIN(price))/AVG(price) * 100) as differenceinprices
FROM `m-orbitzone`
WHERE dep = 'MOW'
AND returnornot = 1
GROUP BY arv, date1, date2
ORDER BY differenceinprices DESC LIMIT 1000
ID price <-- ROUND(AVG(price)) MIN(price) MAX(price) differenceinprices
122841 834 816 534 834 35
122708 783 790 524 821 34
122754 766 796 529 815 34
28528 810 766 512 810 33
28529 799 765 512 799 33
122603 766 798 534 841 33
122848 766 794 529 810 33
122589 778 765 519 778 32
122591 778 768 519 778 32
122749 766 775 529 814 32
28527 752 749 512 773 32
122744 766 773 529 814 32
122843 766 771 529 802 31
Need 'price' to be latest price for this GROUP (row with highest ID)
May be need to do SELECT and then to do one more SELECT from result?
Thank you!
This should do the trick:
SELECT m.ID, price,
ROUND(AVG(price)),
MIN(price),
MAX(price),
ROUND((AVG(price)-MIN(price))/AVG(price) * 100) as differenceinprices
FROM `m-orbitzone` m
INNER JOIN (
SELECT
ID
FROM
`m-orbitzone` m
WHERE ID = (SELECT MAX(ID) FROM `m-orbitzone` sm WHERE m.arv = sm.arv AND m.date1 = sm.date1 AND m.date2 = sm.date2)
) s ON m.ID = s.ID
WHERE dep = 'MOW'
AND returnornot = 1
GROUP BY arv, date1, date2
ORDER BY differenceinprices DESC LIMIT 1000
A good read about the topic is this manual entry.

SQL Server query about updating column

I have asked a similar question previously, but posting a new one as I do not want to confuse other
members, and there is an additional column.
What I am looking for is to update the column ItemActual. This needs to be updated with the difference with ItemValue for the latest CurrentTime for the same StartTime if any.
If there is no other entry for the same StartTime other than the current row, it needs to be the ItemValue itself. The comparisons are only to be done for items with the same name.
For eg, Rownum 283, ItemActual = 347013 (since there is no other row with same StartTime).
This applies to row 235 as well, i.e. ItemActual = 1086054.00
For row 190, this needs to be 664031.00 - 533023.00 (comparing with row 145) = 131008
But for row 10, this will be 532023.00, since there is no earlier entry of same item with same StartTime.
Rownum Name ItemValue CurrentTime StartTime
283 ABC 347013.00 3/05/2012 16:01 29/04/2012 6:29
235 ABC 1086054.00 26/03/2012 14:05 7/03/2012 21:18
190 ABC 664031.00 13/02/2012 13:42 29/01/2012 6:39
145 ABC 533023.00 7/02/2012 14:01 29/01/2012 6:39
100 ABC 532023.00 7/02/2012 13:33 29/01/2012 6:39
55 ABC 532023.00 7/02/2012 12:52 29/01/2012 6:39
10 ABC 532023.00 7/02/2012 12:51 29/01/2012 6:39
310 DEF 351012.00 3/05/2012 16:01 29/04/2012 6:29
261 DEF 1339066.00 26/03/2012 14:05 7/03/2012 21:18
215 DEF 785034.00 13/02/2012 13:42 29/01/2012 6:39
170 DEF 620026.00 7/02/2012 14:01 29/01/2012 6:39
You can try something like this:
;WITH PartData AS
(
SELECT
RowNum, Name, ItemValue, CurrentTime, StartTime,
RX = ROW_NUMBER() OVER(PARTITION BY Name,StartTime ORDER BY CurrentTime DESC)
FROM dbo.YourTable
)
SELECT
p1.RowNum, p1.ItemValue, p1.CurrentTime, p1.StartTime,
RowNumComparedTo = p2.RowNum,
ItemActual = CASE
WHEN p2.RX IS NULL THEN p1.ItemValue
ELSE p1.ItemValue - p2.ItemValue
END
FROM PartData p1
LEFT OUTER JOIN PartData p2 ON p1.StartTime = p2.StartTime
AND p1.Name = p2.Name
AND p2.RX = p1.RX + 1
I get an output something like this:
RowNum ItemValue CurrentTime StartTime RowNumComparedTo ItemActual
190 664031.00 2012-02-13 13:42 2012-01-29 06:39 145 131008.00
145 533023.00 2012-02-07 14:01 2012-01-29 06:39 100 1000.00
100 532023.00 2012-02-07 13:33 2012-01-29 06:39 55 0.00
55 532023.00 2012-02-07 12:52 2012-01-29 06:39 10 0.00
10 532023.00 2012-02-07 12:51 2012-01-29 06:39 NULL 532023.00
215 785034.00 2012-02-13 13:42 2012-01-29 06:39 170 165008.00
170 620026.00 2012-02-07 14:01 2012-01-29 06:39 NULL 620026.00
235 1086054.00 2012-05-03 14:05 2012-03-07 21:18 NULL 1086054.00
261 1339066.00 2012-03-26 14:05 2012-03-07 21:18 NULL 1339066.00
283 347013.00 2012-05-03 16:01 2012-04-29 06:29 NULL 347013.00
310 351012.00 2012-05-03 16:01 2012-04-29 06:29 NULL 351012.00
The solution basically does this:
it creates a CTE (Common Table Expression) and "partitions" your data by Name,StartTime and orders these rows by CurrentTime DESC - so the most recent entry for each Name,StartTime group will get an RX (Row indeX) of 1
it then joins that CTE against itself, shifted by one RX - so I'm comparing RX = 1 to RX = 2 (if present) etc.
if a "shifted" row is present, the difference in the ItemValue values is returned as ItemActual - otherwise the ItemValue from the main row is returned
I hope this solves your problem