select query to get value from a table of an interval - mysql

I have a table with these values...
id colA colB colC
55 00:00:00 NULL NULL
56 01:01:02 0.00007 0.00007
57 02:01:02 0 0.00007
58 03:01:02 0.00006 0
59 15:01:02 0.00012 0.00006
60 16:01:02 -0.00008 0.00012
61 20:59:02 -0.00006 -0.00008
62 21:05:01 0.00005 -0.00006
63 22:01:02 -0.00013 0.00005
64 23:01:02 0.00004 -0.00013
65 00:00:01 -0.00012 0.00004
66 01:01:02 -0.00004 -0.00012
67 02:01:02 0.00006 -0.00004
68 03:01:02 0.00004 0.00006
69 15:01:02 -0.00004 0.00004
70 16:01:02 0 -0.00004
71 23:01:02 -0.00014 0
72 00:00:01 -0.00011 -0.00014
73 01:01:02 -0.00004 -0.00011
74 02:01:02 0.00011 -0.00004
75 03:01:02 0.00005 0.00011
76 15:01:02 0 0.00005
77 16:01:02 -0.00008 0
78 23:01:02 0 -0.00008
79 00:00:01 0.00003 0
80 01:01:02 -0.00009 0.00003
81 02:01:02 -0.00007 0
82 03:01:02 -0.00007 -0.00016
83 15:01:02 0.00044 -0.00007
84 16:01:02 0 0.00044
Now I want to get the SUM of colb, colc on each time colA value changes to 15:01...
The output should be like the following
colA sum(colB) SUM(colC)
15:01:01.582 0.0002500 0.0002000
15:01:01.582 -0.0002800 -0.0001200
15:01:01.582 -0.0001300 -0.0001700
15:01:01.582 0.0001600 -0.0002800
Can anyone please help me with this query.

You can characterize each row by the number of cola values that are 18:01 that appear after it. Then you can group by this number.
In MySQL, the easiest way to get this number is by using variables:
select grp, max(cola), sum(colb), sum(colc)
from (select t.*,
(#grp := #grp + (cola = '18:01')) as grp
from table t cross join (select #grp := 0) vars
order by id desc
) t
group by grp;

Related

Create view with delta for each column in SQL

I have a table named pwrDay containing electric index counters (always growing).
jour
pwrconsohp
pwrconsohc
pwrprod
pwrprodmax
2021-09-26
35 736 527
18 073 331
12 629 677
0
2021-09-27
35 754 125
18 073 331
12 637 154
0
2021-09-28
35 780 113
18 073 331
12 646 963
0
2021-09-29
35 807 081
18 073 331
12 657 084
0
2021-09-30
35 833 193
18 073 331
12 668 804
0
2021-10-01
35 861 259
18 073 331
12 682 444
0
2021-10-02
35 888 342
18 073 331
12 693 908
0
2021-10-03
35 917 218
18 073 331
12 704 696
0
2021-10-04
35 944 869
18 073 331
12 706 056
0
2021-10-05
35 972 043
18 073 331
12 708 309
0
I need to extract the difference between previous and current row (maybe create a view?) The following query works for most days, but it's wrong every first day of month (or if I miss a control day):
SELECT pwr.jour,
(pwr.pwrconsoHP-ifnull(oldpwr.pwrconsoHP, 0)) as deltaconsoHP,
(pwr.pwrconsoHC-ifnull(oldpwr.pwrconsoHC, 0)) as deltaconsoHC,
(pwr.pwrProd-ifnull(oldpwr.pwrProd, 0)) as deltaProd
FROM pwrDay pwr
LEFT OUTER JOIN pwrDay oldpwr ON
(day(pwr.jour)-day(oldpwr.jour)=1 AND MONTH(pwr.jour)=MONTH(oldpwr.jour))
ORDER BY jour;
I also tried this query:
SELECT pwr.jour,
(pwr.pwrconsoHP-LAG(pwr.pwrconsoHP, 0)) as deltaconsoHP,
(pwr.pwrconsoHC-LAG(pwr.pwrconsoHC, 0)) as deltaconsoHC,
(pwr.pwrProd-LAG(pwr.pwrProd, 0)) as deltaProd
FROM pwrDay pwr
ORDER BY jour;
However, it doesn't run at all. I get this error message:
Erreur SQL (1305) : FUNCTION velbus.LAG does not exist
How can I write this query?
SELECT pwr.jour,
(pwr.pwrconsoHP-LAG(pwr.pwrconsoHP, 0) OVER(order by jour)) as deltaconsoHP,
(pwr.pwrconsoHC-LAG(pwr.pwrconsoHC, 0) OVER(order by jour)) as deltaconsoHC,
(pwr.pwrProd-LAG(pwr.pwrProd, 0) OVER(order by jour)) as deltaProd
FROM pwrDay pwr
ORDER BY jour;
give it a try ...

Add values in a lists which is a string column in hive

I have a set of data where a columns consists of lists which is of string data type.
Column_A|Column_B
AAA |1 23 56 89 74 52
BBB |63 99 44 2 80 87 58 63
CCC |96 45 23 84 62 74
Here, In the above data I need to add the values in column B as below:
Column_A|Column_B |Column_C
AAA |1 23 56 89 74 52 |295
BBB |63 99 44 2 80 87 58 63|496
CCC |96 45 23 84 62 74 |384
I have used cast function and converted the data type from string to int using the below query.
select Column_A,cast (Column_B as INT) as Column_B from Xyz
But summing the values is a great challenge.
Can someone help me out?
I'm learning RegEx too.. Is there any possibility to use RegEx?
Explode your column using split by space and aggregate.
This is demo in Hive:
with your_data as
(
select Column_A,Column_B from
(
select stack(3,
'AAA','1 23 56 89 74 52',
'BBB','63 99 44 2 80 87 58 63',
'CCC','96 45 23 84 62 74'
) as (Column_A,Column_B)
)s
) --Use your table instead of this CTE
select Column_A,Column_B, sum(cast(b.val_b as int)) as Column_C
from your_data a
lateral view outer explode(split(Column_B,' ')) b as val_b
group by Column_A,Column_B;
Result:
OK
AAA 1 23 56 89 74 52 295
BBB 63 99 44 2 80 87 58 63 496
CCC 96 45 23 84 62 74 384
Time taken: 53.228 seconds, Fetched: 3 row(s)
Alternatively, if the maximum number of elements in the list is fixed, you can do the same without explode, it will work much faster:
create temporary macro cast_value(s string) nvl(cast(s as int),0);
with your_data as
(
select Column_A,Column_B from
(
select stack(3,
'AAA','1 23 56 89 74 52',
'BBB','63 99 44 2 80 87 58 63',
'CCC','96 45 23 84 62 74'
) as (Column_A,Column_B)
)s
) --Use your table instead of this CTE
select Column_A,Column_B,
cast_value(col_B_array[0])+
cast_value(col_B_array[1])+
cast_value(col_B_array[2])+
cast_value(col_B_array[3])+
cast_value(col_B_array[4])+
cast_value(col_B_array[5])+
cast_value(col_B_array[6])+
cast_value(col_B_array[7])+
cast_value(col_B_array[8])+
cast_value(col_B_array[9]) as Column_C
from(
select Column_A,Column_B, split(Column_B,' ') col_B_array
from your_data a
)s
Result:
OK
AAA 1 23 56 89 74 52 295
BBB 63 99 44 2 80 87 58 63 496
CCC 96 45 23 84 62 74 384
Time taken: 0.82 seconds, Fetched: 3 row(s)

Filter rows in mysql

I'm trying to solve a MySQL problem without going crazy. Not sure if it is feasible or not.
Data come from a door/light sensor to detect if toilet is occupied. When door is closed or opened, I get the info + light info. If I have info of closed door and light<10, I say that toilet is not occupied, if light>10, toilet is occupied, and if door is open, toilet is not occupied.
Here is an example of my data :
id wc_id door_open light time
138 0 1 64 2018-10-10 12:28:51
139 0 0 58 2018-10-10 12:34:00
140 0 0 54 2018-10-10 12:34:38
141 0 1 68 2018-10-10 12:35:11
142 0 1 3 2018-10-10 12:35:36
143 0 0 60 2018-10-10 12:37:56
144 0 0 60 2018-10-10 12:37:57
145 0 0 57 2018-10-10 12:38:30
146 0 1 65 2018-10-10 12:43:53
147 0 1 3 2018-10-10 12:44:17
148 0 0 63 2018-10-10 13:10:55
149 0 0 59 2018-10-10 13:11:16
150 0 1 71 2018-10-10 13:12:09
151 0 1 4 2018-10-10 13:12:14
152 0 1 1 2018-10-10 13:15:07
153 0 0 62 2018-10-10 13:17:18
154 0 0 58 2018-10-10 13:18:01
155 0 1 68 2018-10-10 13:19:20
156 0 1 3 2018-10-10 13:19:56
157 0 1 42 2018-10-10 13:26:41
158 0 0 63 2018-10-10 13:26:44
159 0 0 58 2018-10-10 13:27:39
160 0 1 71 2018-10-10 13:27:40
161 0 1 3 2018-10-10 13:28:37
The idea is at the end to have only a series of door_open to 0 to 1, it's not possible to have two 0 or two 1 consecutively.
So I need to keep first door_open=0 with light>10 following a door_open=1, and first door_open=1 after door_open=0, whatever light value.
Is it possible with MySQL? I use MariaDB 10.3.9.
Thanks for your ideas.
The output should be like that :
id wc_id door_open light time
139 0 0 58 12:34:00
141 0 1 68 12:35:11
143 0 0 60 12:37:56
146 0 1 65 12:43:53
148 0 0 63 13:10:55
150 0 1 71 13:12:09
153 0 0 62 13:17:18
155 0 1 68 13:19:20
158 0 0 63 13:26:44
160 0 1 71 13:27:40
(I simplified the time, it's not really important here)
Here is a fiddle
This query should do what you want. It uses a MySQL variable to delay the value of door_open by 1 row, and then returns rows where door_open=0 with light>10 following a door_open=1, and first door_open=1 after door_open=0, whatever light value:
SELECT events.*, #door_open := door_open
FROM events
JOIN (SELECT #door_open := 1) do
WHERE #door_open = 0 AND door_open = 1 OR
#door_open = 1 AND door_open = 0 AND light > 10
Output (from your fiddle data):
id toilet_id door_open light time #door_open := door_open
101 0 false 62 2018-10-10T11:39:31Z 0
103 0 true 69 2018-10-10T11:39:34Z 1
104 0 false 62 2018-10-10T11:42:16Z 0
106 0 true 68 2018-10-10T11:45:50Z 1
109 0 false 56 2018-10-10T12:13:11Z 0
Updated SQLFiddle
Here is the potential answer to my problem, after working on Nick solution. I had to reorder my table (after deleting rows) to avoid an order mess.
select es.id,
es.idNext,
es.toilet_id,
es.time,
es.nextTime,
timediff(es.nextTime, es.time) AS duration
from (
SELECT id, toilet_id, time,
#door_open := door_open as door_open,
lead(id, 1) OVER(ORDER BY id) idNext,
lead(time, 1) OVER(ORDER BY id) nextTime
FROM events e
JOIN (SELECT #door_open := 1) do
WHERE #door_open = 0 AND door_open = 1 OR
#door_open = 1 AND door_open = 0 AND light > 20
) es
where
es.door_open=0 and
timediff(es.nextTime, es.time)>5
Next thing is to update the query to use a partition over toilet_id to separate data from each id.

MySql sort query with multiple fields

I have two tables "activity_stats" & "activity_stats_values"
activity_stats table
# id, activity_id, kyf_id, kyf_sort
618 84 5 1
619 84 6 2
638 84 4 3
activity_stats_values table
# id, activity_id, player_id, kyf_id, value
2563 84 46 5 45
2564 84 46 6 60
2587 84 47 5 10
2588 84 47 6 25
2589 84 49 5 10
2590 84 49 6 40
2591 84 48 5 30
2592 84 48 6 15
2594 84 46 4 NULL
2595 84 47 4 80
2596 84 48 4 NULL
2597 84 49 4 NULL
Requirement
players should be sorted by values in descending order. Meaning the player with highest value of first keyfigure(kyf_id , kyf_id position based on field "kyf_sort" of table "activity_stats") should be on top (then second key figure, then third key figure).
Expected output
# id, activity_id, player_id, kyf_id, value kyf_sort
2563 84 46 5 45 1
2564 84 46 6 60 2
2594 84 46 4 NULL 3
2591 84 48 5 30 1
2592 84 48 6 15 2
2596 84 48 4 NULL 3
2589 84 49 5 10 1
2590 84 49 6 40 2
2597 84 49 4 NULL 3
2587 84 47 5 10 1
2588 84 47 6 25 2
2595 84 47 4 80 3
OR playes ids in order [46,48,49,47]
I tried the following query
SELECT ac_st_v.activity_id,ac_st_v.player_id,ac_st_v.value,ac_st.kyf_id,ac_st.kyf_sort,pl.first_name ,
(select max(value)
from activity_stats_values
where activity_id=ac_st_v.activity_id
and kyf_id=ac_st.kyf_id
group by activity_id) as m_value
FROM teamplayer.activity_stats_values as ac_st_v
JOIN teamplayer.activity_stats as ac_st
ON ac_st_v.activity_id=ac_st.activity_id
AND ac_st_v.kyf_id=ac_st.kyf_id
JOIN teamplayer.players as pl
ON ac_st_v.player_id=pl.id
where ac_st_v.activity_id= 84
order by ac_st_v.player_id,ac_st.kyf_sort,m_value
Is there any way to sort the values like this?

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.