Finding a running Difference in Columns with mySQL - 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

Related

Find ratio of flags for every associated id from table_a.canon_id using mysql joins?

table_a
user_id canon_id ratio (count of 1 / total)
1 1000 0.33
2 1000 0.33
3 1000 0.33
11 4344 0.50
88 4344 0.50
7 2023 0
8 2023 0
10 2023 0
12 3333 0.80
17 3333 0.80
18 3333 0.80
19 3333 0.80
20 3333 0.80
table_b
user_id flag
1 0
2 0
3 1
11 1
88 0
14 0
7 1
8 1
10 1
12 1
17 1
18 1
19 1
20 0
In the above case, how can I join tables and populate the table_a.ratio by using flags from another MySQL table? the formula for ratio is (count of 1 / total user_ids associated with that canon_id)
If you are running MySQL 8.0, you can use window functions. avg() comes to mind:
select a.*, avg(b.flag) over(partition by a.canon_id) ratio
from table_a a
left join table_b b on b.user_id = a.user_id
In earlier versions, a correlated subquery might be an acceptable solution:
select
a.*,
(
select avg(b1.flag)
from table_a a1
left join table_b b1 on b1.user_id = b.user_id
where a1.canon_id = a.canon_id
) ratio
from table_a a

how to display Each record 4 for each id column

id serviceid name cost date
201 15 X 50 25.12.2016
201 15 Y 55 29.11.2016
201 120 Z 50 27.11.2016
201 19 w 50 22 .11.2016
201 158 p 50 23.11.2016
201 18 q 50 21.11.2016
201 16 rs 50 24.11.2016
201 81 rs 50 2.11.2016
202 18 X 50 25.12.2016
202 18 Y 55 29.11.2016
202 15 Z 50 27.11.2016
202 19 w 50 22 .11.2016
203 15 p 50 23.11.2016
203 18 q 50 21.11.2016
203 16 rs 50 24.11.2016
0 81 rs 50 2.11.2016
Desire Output :
id serviceid name cost date
201 15 X 50 25.12.2016
201 15 Y 55 29.11.2016
201 120 Z 50 27.11.2016
201 16 rs 50 24.11.2016
202 18 X 50 25.12.2016
202 18 Y 55 29.11.2016
202 15 Z 50 27.11.2016
202 19 w 50 22 .11.2016
203 15 p 50 23.11.2016
203 18 q 50 21.11.2016
203 16 rs 50 24.11.2016
0 81 rs 50 2.11.2016
i want to display each record 4 - 4 record service for each id i am trying to apply using self Join but there is Problem coming please tell or suggest me how to ac-chive for this.
SELECT a.*
FROM mytable AS a
WHERE
(SELECT COUNT(*) FROM mytable AS b
WHERE b.id = a.id and b.serviceid >= a.serviceid) <= 4
ORDER BY a.id , a.date
this query am trying but i am unable to fetch it for each id there should top 4 service id based on date.
To make your desired result, I think you should use mysql variable like this:
select
t1.*
from mytable t1
join (
select
`id`,
`serviceid`,
`name`,
`cost`,
`date`,
#rowno := case when #grp = `id` then #rowno + 1 else 1 end as rowno,
#grp := `id`
from mytable
cross join (select #rowno:=0, #grp:=null) v
order by `id`, `date` desc) t2
on t1.id = t2.id
and t1.`date` = t2.`date`
and t2.rowno < 5
and this seems to be a classic top x record in each group issue, take a look of How to select the first/least/max row per group in SQL

Need to fetch a MySQL result

I have following MySQL table structure,
id product_id filter_tag_id
14 1 48
17 3 49
18 10 49
19 10 54
20 11 49
21 11 55
22 12 49
23 12 56
24 9 48
25 9 52
26 6 48
27 6 53
28 7 48
29 7 56
30 8 48
31 8 53
32 13 48
33 13 52
34 14 48
35 14 54
36 14 55
37 15 48
38 15 55
i need to fetch only those product_id's which have same filter_tag_id's,
For example only one product_id (9 and 13) having the same filter_tag_id (48 and 52), so I need to fetch only product_id 9 and 13, I'm trying following query, but no success yet.
select product_id from filter_data where filter_tag_id=52 AND filter_tag_id=48;
select product_id from filter_data where filter_tag_id in (52,48);
First query return no result and second one returning wrong results
Use self-join. It looks like more complicated than GROUP BY, but it is faster than group-by. Because with GROUP BY approach, those which only has 48 or 52 should be groupped that is not unneeded rows.
SELECT t1.product_id
FROM filter_data t1 INNER JOIN filter_data t2 ON t1.product_id = t2.product_id
WHERE t1.filter_tag_id = 48 AND t2.filter_tag_id = 52;
If what you want is to find only product_ids having filter_tag_id values equal to 48 and 52 and nothing else but these two values, then try:
SELECT product_id
FROM mytable
GROUP BY product_id
HAVING COUNT(CASE WHEN filter_tag_id = 48 THEN 1 END) > 0 AND
COUNT(CASE WHEN filter_tag_id = 52 THEN 1 END) > 0 AND
COUNT(CASE WHEN filter_tag_id NOT IN (48,52) THEN 1 END) = 0
Demo here
use GROUP BY
Select product_id,COUNT(DISTINCT filter_tag_id) filter_match
from filter_data where filter_tag_id in (52,48)
GROUP BY product_id
HAVING filter_match = 2
the value of filter_match is count you will pass in condition

Tricky SQL query - need to get time frames [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I am stumbled upon a problem, when I need a query which will produce a list of speeding time frames.
Here is the data example
[idgps_unit_location] [dt] [idgps_unit] [lat] [long] [speed_kmh]
26 10/18/2012 18:53 2 47 56 30
27 10/18/2012 18:53 2 49 58 31
28 10/18/2012 18:53 2 28 37 15
29 10/18/2012 18:54 2 56 65 33
30 10/18/2012 18:54 2 152 161 73
31 10/18/2012 18:55 2 134 143 64
32 10/18/2012 18:56 2 22 31 12
36 10/18/2012 18:59 2 98 107 47
37 10/18/2012 18:59 2 122 131 58
38 10/18/2012 18:59 2 91 100 44
39 10/18/2012 19:00 2 190 199 98
40 10/18/2012 19:01 2 194 203 101
41 10/18/2012 19:02 2 182 191 91
42 10/18/2012 19:03 2 162 171 78
43 10/18/2012 19:03 2 174 183 83
44 10/18/2012 19:04 2 170 179 81
45 10/18/2012 19:05 2 189 198 97
46 10/18/2012 19:06 2 20 29 10
47 10/18/2012 19:07 2 158 167 76
48 10/18/2012 19:08 2 135 144 64
49 10/18/2012 19:08 2 166 175 79
50 10/18/2012 19:09 2 9 18 5
51 10/18/2012 19:09 2 101 110 48
52 10/18/2012 19:09 2 10 19 7
53 10/18/2012 19:10 2 32 41 20
54 10/18/2012 19:10 1 54 63 85
55 10/19/2012 19:11 2 55 64 50
I need a query that would convert this table into the following report that shows frames of time when speed was >80:
[idgps_unit] [dt_start] [lat_start] [long_start] [speed_start] [dt_end] [lat_end] [long_end] [speed_end] [speed_average]
2 10/18/2012 19:00 190 199 98 10/18/2012 19:02 182 191 91 96.66666667
2 10/18/2012 19:03 174 183 83 10/18/2012 19:05 189 198 97 87
1 10/18/2012 19:10 54 63 85 10/18/2012 19:10 54 63 85 85
Now, what have I tried? I tried putting this into separate tables, queries and do some joins... Nothing works and I am very frustrated... I am not even sure if this could be done via the query. Asking for the expert help!
You were right, it is fairly tricky, but I think I've managed it:
SELECT s.idgps_unit,
MIN(s.dt) AS DT_Start,
MIN(CASE WHEN s.RowNumber = 1 THEN s.Lat END) AS Lat_Start,
MIN(CASE WHEN s.RowNumber = 1 THEN s.Long END) AS Long_Start,
MIN(CASE WHEN s.RowNumber = 1 THEN s.Speed_kmh END) AS Speed_Start,
MAX(s.dt) AS dt_end,
MIN(CASE WHEN s.RowNumber = MaxRowNumber THEN s.Lat END) AS Lat_End,
MIN(CASE WHEN s.RowNumber = MaxRowNumber THEN s.Long END) AS Long_End,
MIN(CASE WHEN s.RowNumber = MaxRowNumber THEN s.Speed_kmh END) AS Speed_End,
AVG(Speed_kmh) AS Speed_Average
FROM ( SELECT T.*,
#i:= CASE WHEN Speed_Kmh > 80 AND #b = 0 THEN #i + 1 ELSE #i END AS IntervalID,
#r:= CASE WHEN Speed_Kmh > 80 AND #b = 0 THEN 1 ELSE #r + 1 END AS RowNumber,
#b:= CASE WHEN Speed_Kmh> 80 THEN 1 ELSE 0 END AS IntervalCheck
FROM T,
(SELECT #i:= 0) i,
(SELECT #r:= 0) r,
(SELECT #b:= 0) b
ORDER BY dt, idgps_unit_location
) s
INNER JOIN
( SELECT IntervalID, MAX(RowNumber) AS MaxRowNumber
FROM ( SELECT T.*,
#i:= CASE WHEN Speed_Kmh > 80 AND #b = 0 THEN #i + 1 ELSE #i END AS IntervalID,
#r:= CASE WHEN Speed_Kmh > 80 AND #b = 0 THEN 1 ELSE #r + 1 END AS RowNumber,
#b:= CASE WHEN Speed_Kmh> 80 THEN 1 ELSE 0 END AS IntervalCheck
FROM T,
(SELECT #i:= 0) i,
(SELECT #r:= 0) r,
(SELECT #b:= 0) b
ORDER BY dt, idgps_unit_location
) d
WHERE IntervalCheck = 1
GROUP BY IntervalID
) MaxInt
ON MaxInt.IntervalID = s.IntervalID
WHERE s.IntervalCheck = 1
GROUP BY s.IntervalID, s.idgps_unit;
The key is in this part:
SELECT T.*,
#i:= CASE WHEN Speed_Kmh > 80 AND #b = 0 THEN #i + 1 ELSE #i END AS IntervalID,
#r:= CASE WHEN Speed_Kmh > 80 AND #b = 0 THEN 1 ELSE #r + 1 END AS RowNumber,
#b:= CASE WHEN Speed_Kmh> 80 THEN 1 ELSE 0 END AS IntervalCheck
FROM T,
(SELECT #i:= 0) i,
(SELECT #r:= 0) r,
(SELECT #b:= 0) b
ORDER BY dt, idgps_unit_location
Each time a row is encountered where the speed is over it sets the variable #b to 1, if this variable was 0 before it assigns the row a new intervalID, if it does this it begins numbering the row at 1 again, so you end up with something like this:
[idgps_unit_location] [dt] [idgps_unit] [lat] [long] [speed_kmh] [IntervalID] RowNumber IntervalCheck
37 10/18/2012 18:59 2 122 131 58 1 1 0
38 10/18/2012 18:59 2 91 100 44 1 2 0
39 10/18/2012 19:00 2 190 199 98 2 1 1
40 10/18/2012 19:01 2 194 203 101 2 2 1
41 10/18/2012 19:02 2 182 191 91 2 3 1
42 10/18/2012 19:03 2 162 171 78 2 4 0
43 10/18/2012 19:03 2 174 183 83 3 1 1
You then need to elimate all rows where the speed is under 80 (WHERE IntervalCheck = 1), and finally you can use aggregate functions along with CASE to find the rows where RowNumber is 1 (the first row of speeding), or the highest rownumber for that interval (the last row of speeding). The join at the end simply repeats the process to find what the maximum rownumber is for each intervalID.
Example on SQL Fiddle
Have you tried something like this (omitting the average speed calculation):
SELECT * FROM (
SELECT
start.idgps_unit,
start.dt dt_start,
...
end.dt dt_end,
...
(...) average_speed
FROM
your_table start,
your_table end
WHERE
start.dt < end.dt
)
WHERE average_speed > 80
This will get you a lot of overlapping timeframes, not sure whether this is desired or not. If not, you could filter with NOT EXISTS:
SELECT *
FROM (query_above) timeframes
WHERE NOT EXISTS (
SELECT *
FROM (query_above) longer_timeframes
WHERE
longer_timeframes.dt_start < timeframes.dt_end OR
longer_timeframes.dt_end > timeframes.dt_end
)
This might still get you some overlap, e.g. if you go 60 from 19:00 to 19:03, 100 from 19:03 to 19:07, and again 60 from 19:07 to 19:10. Then you have two maximum-length time intervals in which average speed was greater than 80, one from 19:00 to 19:07, the other from 19:03 to 19:10.

Sorting varchar fields for mysql database

Trying to sort the following TEAM_TOTAL Column Desc
MATCHID TEAM_TOTAL
---------- -----------------
573 Total 112
573 Total 2 for 115
574 Total 9 for 97
574 Total 2 for 100
575 Total 9 for 129
575 Total 9 for 101
576 Total 4 for 191
576 Total 9 for 160
577 Total 8 for 157
577 Total 7 for 137
578 Total 6 for 193
578 Total 119
But the problem is TEAM_TOTAL is varchar, is there a way with query alone I can get the results in the sorted desc order.
More over there is a text as well in that column. I am running out of ideas to get this up
Result should have beeen like the below Result Set
MATCHID TEAM_TOTAL
---------- -----------------
578 Total 6 for 193
576 Total 4 for 191
576 Total 9 for 160
577 Total 8 for 157
577 Total 7 for 137
575 Total 9 for 129
578 Total 119
573 Total 2 for 115
573 Total 112
575 Total 9 for 101
574 Total 2 for 100
574 Total 9 for 97
Give this a try:
select * from t
order by substring(
team_total, locate('for', team_total) +
if(locate('for', team_total) > 0, 4, 7))+0 desc
Fiddle here.
Try to extract the integer (string after the last space):
-- 'Total 112' - extracts 112
SELECT SUBSTRING('Total 112', LENGTH('Total 112') - LOCATE(' ', REVERSE('Total 112')));
-- 'Total 6 for 193' - extracts 193
SELECT SUBSTRING('Total 6 for 193', LENGTH('Total 6 for 193') - LOCATE(' ', REVERSE('Total 6 for 193')));
Now, you can convert that string to a number and then order by it.
SELECT * FROM teams
ORDER BY
CAST(SUBSTRING(TEAM_TOTAL, LENGTH(TEAM_TOTAL) - LOCATE(' ', REVERSE(TEAM_TOTAL))) AS INT) DESC