Trailing n-day cumulative sum in mysql - mysql

I have this structure:
+--------------------------------------+---------------------+--------+-------------+-------------+
| id | start | User | billedHours | trail90dsum |
+--------------------------------------+---------------------+--------+-------------+-------------+
| 2e88f9f9-2543-11eb-9d57-02b150913215 | 2018-10-04 11:00:00 | User 1 | 15.30 | NULL |
| 2e89af0a-2543-11eb-9d57-02b150913215 | 2018-10-09 12:00:00 | User 1 | 0.40 | NULL |
| 2e8a400b-2543-11eb-9d57-02b150913215 | 2018-10-09 17:00:00 | User 2 | 0.60 | NULL |
| 2e8ae87d-2543-11eb-9d57-02b150913215 | 2018-10-25 17:30:00 | User 2 | 0.30 | NULL |
| 2e8ba472-2543-11eb-9d57-02b150913215 | 2018-10-27 15:00:00 | User 3 | 1.20 | NULL |
| 2e975c93-2543-11eb-9d57-02b150913215 | 2018-10-29 17:30:00 | User 3 | 0.30 | NULL |
| 2e980477-2543-11eb-9d57-02b150913215 | 2018-11-02 13:30:00 | User 1 | 1.90 | NULL |
| 2e98a874-2543-11eb-9d57-02b150913215 | 2018-11-03 12:00:00 | User 2 | 0.70 | NULL |
| 2e993a7d-2543-11eb-9d57-02b150913215 | 2018-11-04 13:30:00 | User 3 | 1.30 | NULL |
| 2ea9fa03-2543-11eb-9d57-02b150913215 | 2018-11-11 11:00:00 | User 1 | 0.90 | NULL |
+--------------------------------------+---------------------+--------+-------------+-------------+
I am looking for an UPDATE query that will fill the trail90dsum field with SUM(billedHours) for each user within the trailing 90 days (as of each start date).
I was able to construct a SELECT query with a join for reporting the data, but I can't transform it to work in the UPDATE syntax.
Thanks,
Phillip

Thanks for all the help. This query got the job done:
UPDATE mytable dst JOIN
(SELECT t1.user, t1.start, t1.billedHours, SUM(t2.billedHours) as last90
FROM mytable as t1 JOIN mytable as t2 ON DATEDIFF(t1.start, t2.start) BETWEEN 0
AND 90 WHERE t1.user=t2.user
GROUP BY t1.user, t1.start, t1.billedHours) src
SET dst.trail90dsum=src.last90
WHERE src.start=dst.start and src.user=dst.user
Thanks, -P

Related

MYSQL - How may i subtract two columns on two different rows, on the same table?

I have a select taht brings the result like this:
+-----------+------------+--------------+
| parking_id| start_time | end_time |
+-----------+------------+--------------+
| 38 | 09:15:00 | 10:32:00 |
| 57 | 11:45:00 | 13:21:00 |
| 33 | 14:40:00 | 16:35:00 |
| 15 | 17:13:00 | 19:15:00 |
| 68 | 20:54:00 | NULL |
+-----------+------------+--------------+
As you can see the IDs dont follow a linear order, but wat i really need is a select that brings me the time between the new start_time and end_time for the last inserted , that follows this non linear order, so i need a select that brings me this:
+-----------+------------+--------------+----------------+
| parking_id| start_time | end_time | time_btw_parks |
+-----------+------------+--------------+----------------+
| 38 | 09:15:00 | 10:32:00 | NULL |
| 57 | 11:45:00 | 13:21:00 | 01:13:00 |
| 33 | 14:40:00 | 16:35:00 | 01:19:00 |
| 15 | 17:13:00 | 19:15:00 | 00:38:00 |
| 68 | 20:54:00 | NULL | 01:39:00 |
+-----------+------------+--------------+----------------+
Doesn't have to necessary be select query. Anything that solves it would help.
For this sample data you can use timediff() function:
select t.parking_id, t.start_time, t.end_time,
timediff(t.start_time, max(tt.end_time)) time_btw_parks
from tablename t left join tablename tt
on t.start_time > tt.end_time
group by t.parking_id, t.start_time, t.end_time
order by t.start_time
See the demo.
Results:
| parking_id | start_time | end_time | time_btw_parks |
| ---------- | ---------- | -------- | -------------- |
| 38 | 09:15:00 | 10:32:00 | |
| 57 | 11:45:00 | 13:21:00 | 01:13:00 |
| 33 | 14:40:00 | 16:35:00 | 01:19:00 |
| 15 | 17:13:00 | 19:15:00 | 00:38:00 |
| 68 | 20:54:00 | | 01:39:00 |

How to determine that the date is included in a particular month and to join the tables?

I have the first table which stores hourly information about the status of the object.
| TIME_KEY | ID_OBJECT | STATUS |
|---------------------|-----------|--------|
| 2018-01-01 00:00:00 | 1 | IN |
| 2018-01-01 00:00:00 | 2 | OUT |
| 2018-01-01 01:00:00 | 1 | OUT |
| 2018-01-01 01:00:00 | 2 | IN |
| 2018-02-01 00:00:00 | 1 | IN |
| 2018-02-01 00:00:00 | 2 | OUT |
| 2018-02-01 01:00:00 | 1 | OUT |
| 2018-02-01 01:00:00 | 2 | IN |
The second table stores the code name of the object in a certain month.
| MONTH_KEY | SITE_ID | NAME |
|---------------------|-----------|------------|
| 2018-01-01 | 1 | Apple |
| 2018-01-01 | 2 | HP |
| 2018-02-01 | 1 | Samsung |
| 2018-02-01 | 2 | Blackberry |
How correctly join this two table and return such result?
| TIME_KEY | ID_OBJECT | STATUS | NAME |
|---------------------|-----------|--------|------------|
| 2018-01-01 00:00:00 | 1 | IN | Apple |
| 2018-01-01 00:00:00 | 2 | OUT | HP |
| 2018-01-01 01:00:00 | 1 | OUT | Apple |
| 2018-01-01 01:00:00 | 2 | IN | HP |
| 2018-02-01 00:00:00 | 1 | IN | Samsung |
| 2018-02-01 00:00:00 | 2 | OUT | Blackberry |
| 2018-02-01 01:00:00 | 1 | OUT | Samsung |
| 2018-02-01 01:00:00 | 2 | IN | Blackberry |
you can convert date to month and can join
select t2.TIME_KEY,t1.ID_OBJECT,STATUS,NAME
FROM table1 t1 JOIN
table2 t2 on month(t1.TIME_KEY)=month(t2.TIME_KEY) and t1.ID_OBJECT=t2.SITE_ID
You can use a correlated subquery:
select t1.*,
(select t2.name
from table2 t2
where t2.site_id = t1.object_id and
t1.time_key >= t2.month_key
order by t2.month_key desc
limit 1
) as name
from table1 t1;
This will take the most recent name, even if it is not in the current month. I am guessing that is desirable behavior.
You need JOIN & conversations :
SELECT T1.TIME_KEY, T1.ID_OBJECT, T1.STATUS, T2.NAME
FROM table1 T1 INNER JOIN
table2 T2
ON T1.ID_OBJECT = T2.SITE_ID AND
CAST(T2.MONTH_KEY AS DATE) = CAST(T1.TIME_KEY AS DATE);

MySQL Update with Select Join

I have following tables as the simplest form.
Table "pro_details_old"
+------+------------+--------+------------+
| id | project_no | amount | pro_date |
+------+------------+--------+------------+
| 1000 | 001/001 | 50000 | 2018-10-01 |
| 1001 | 001/002 | 25000 | 2018-10-06 |
| 1002 | 002/004 | 75000 | 2018-10-12 |
| 1003 | 002/005 | 65000 | 2018-09-22 |
| 1004 | 002/006 | 10000 | 2018-08-17 |
| 1005 | 003/002 | 12000 | 2018-10-08 |
| 1006 | 003/003 | 145000 | 2018-07-01 |
+------+------------+--------+------------+
Table "pro_details_new"
+------+------------+--------+----------+
| id | project_no | amount | pro_date |
+------+------------+--------+----------+
| 1050 | 001/001 | 50000 | |
| 1051 | 001/002 | 25000 | |
| 1052 | 002/004 | 75000 | |
| 1053 | 002/005 | 65000 | |
| 1054 | 002/006 | 10000 | |
| 1055 | 003/002 | 12000 | |
| 1056 | 003/003 | 145000 | |
+------+------------+--------+----------+
02) So, I need to update issued_date column in "issues" table while comparing project_no of above 02 tables. ref_no & amount columns of "issues" table are already inserted. Expected output as follows.
+----+--------+--------+-------------+
| id | ref_no | amount | issued_date |
+----+--------+--------+-------------+
| 1 | 1050 | 50000 | 2018-10-01 |
| 2 | 1051 | 25000 | 2018-10-06 |
| 3 | 1052 | 75000 | 2018-10-12 |
| 4 | 1053 | 65000 | 2018-09-22 |
| 5 | 1054 | 10000 | 2018-08-17 |
| 6 | 1055 | 12000 | 2018-10-08 |
| 7 | 1056 | 145000 | 2018-07-01 |
+----+--------+--------+-------------+
03) I used the following query.
insert into issues
set issued_date =
(select pro_date
from pro_details_old
where
pro_details_old.project_no = pro_details_new.project_no)
left join pro_details_new on pro_details_new.id = issues.ref_no
04) I can not understand what is the wrong point. Can anyone help me ?
Update Query using join
Select the particular data which you want to update in issuestable using condition
update
issuestable as t3
join (
select
t1.id,
t1.pro_date
from
pro_details_old as t1
inner join pro_details_new as t2 on t1.project_no = t2.project_no
) t4 on t4.id = t3.ref_no
set
t3.issued_date = t4.pro_date
Insert Query
If you want to populate fresh data form pro_details_old & pro_details_new then you can use below insert query
INSERT INTO issues (ref_no, amount, issued_date)
VALUES
(
select
t1.id as ref_no,
t1.amount,
t1.pro_date as issued_date
from
pro_details_old as t1
inner join pro_details_new as t2 on t1.project_no = t2.project_no
)

copy specific row from multiple table into another table in sql

I want to copy a specific row from tables temperature, rules and schedule to stats table.
In temperature table, I want the latest temperature which is 18.6
mysql> SELECT * FROM currenttemp ORDER BY `timestamp` DESC limit 10 ;
+---------------------+-----------------+-------------+----------+----------+
| timestamp | sensor | currenttemp | humidity | pressure |
+---------------------+-----------------+-------------+----------+----------+
| 2017-03-25 15:28:03 | sensor-1stFloor | 18.6 | 49.85 | 1021.26 |
| 2017-03-25 15:27:03 | sensor-1stFloor | 18.7 | 49.81 | 1021.26 |
| 2017-03-25 15:26:03 | sensor-1stFloor | 18.8 | 49.82 | 1021.26 |
| 2017-03-25 15:25:03 | sensor-1stFloor | 18.9 | 49.85 | 1021.22 |
| 2017-03-25 15:24:03 | sensor-1stFloor | 18.99 | 49.83 | 1021.21 |
| 2017-03-25 15:23:03 | sensor-1stFloor | 18.61 | 49.85 | 1021.18 |
| 2017-03-25 15:22:02 | sensor-1stFloor | 18.62 | 49.8 | 1021.3 |
| 2017-03-25 15:21:02 | sensor-1stFloor | 18.63 | 49.82 | 1021.39 |
| 2017-03-25 15:20:03 | sensor-1stFloor | 18.61 | 49.82 | 1021.28 |
| 2017-03-25 15:19:03 | sensor-1stFloor | 18.62 | 49.82 | 1021.37 |
+---------------------+-----------------+-------------+----------+----------+
In rules table, I want the targettemp for schedule 4 which is 40
mysql> SELECT * FROM rules limit 10 ;
+----+----------+--------+------------+
| id | schedule | sensor | targettemp |
+----+----------+--------+------------+
| 1 | 4 | 1 | 40 |
| 2 | 5 | 1 | 5 |
+----+----------+--------+------------+
In schedule table, I want the endtime for id 4 which is 10:00:00
mysql> SELECT * FROM schedules limit 10 ;
+----+--------------+-----------+--------------+-----------+----------+---------+------------+--------+
| id | friendlyname | dayofweek | pretimestart | timestart | endtime | enabled | targettemp | sensor |
+----+--------------+-----------+--------------+-----------+----------+---------+------------+--------+
| 4 | test | 1111110 | 00:00:00 | 00:00:00 | 10:00:00 | 1 | 30 | 1 |
| 5 | sun | 0000001 | 00:00:00 | 00:00:00 | 20:00:00 | 0 | 0 | |
+----+--------------+-----------+--------------+-----------+----------+---------+------------+--------+
I then want to insert these data to the stats table
currenttemp which is 18.6
targettemp for schedule 4 which is 40
endtime for id 4 which is 10:00:00
the timestamp is done automatically
state will be between ON and OFF
please look at the 1st row in stats table as example from the data copied from the above tables.
mysql> SELECT * FROM stats limit 10 ;
+---------------------+-------------+------------+----------+-------+
| timestamp | currenttemp | targettemp | endtime | state |
+---------------------+-------------+------------+----------+-------+
| 2017-03-25 15:41:46 | 18.6 | 40 | 10:00:00 | OFF |
| 2017-03-19 16:53:05 | 16.83 | 5 | 00:00:00 | OFF |
| 2017-03-19 16:54:14 | 16.83 | 40 | 00:00:00 | ON |
| 2017-03-19 20:04:07 | 16.58 | 40 | 00:00:00 | ON |
| 2017-03-19 20:04:15 | 16.58 | 5 | 00:00:00 | OFF |
| 2017-03-19 20:06:29 | 16.58 | 5 | 00:00:00 | OFF |
| 2017-03-19 20:34:28 | 16.54 | 5 | 00:00:00 | OFF |
| 2017-03-19 20:34:56 | 16.54 | 5 | 00:00:00 | OFF |
| 2017-03-19 20:35:26 | 16.54 | 40 | 00:00:00 | ON |
| 2017-03-19 20:38:05 | 16.54 | 40 | 00:00:00 | ON |
+---------------------+-------------+------------+----------+-------+
I will have 2 queries. One with the state OFF and one with the state ON.
Your question is unclear because the relationship between temperature and the other tables is unclear. Let me assume that there is a join key to schedules. If so, the query you want would look something like this:
INSERT INTO stats (currenttemp, targettemp, endtime)
SELECT t.temperature, r.targettemp, s.timeend
FROM schedules s INNER JOIN
rules r
ON s.id = r.schedule INNER JOIN
temperature t
ON t.schedule = s.id
WHERE s.id = 4 AND
t.timestamp = (SELECT MAX(t2.timestamp)
FROM temperature t2
WHERE t2.schedule = t.schedule
);
this seems to work
INSERT INTO stats (currenttemp,targettemp,endtime,state)
SELECT
temperature,r.targettemp,s.timeend,'OFF'
FROM
schedules s
INNER JOIN rules r
ON s.id = r.schedule
INNER JOIN temperature
WHERE timestamp = (SELECT MAX(timestamp) FROM temperature)
AND s.id = 4
i can see now in my stats table
mysql> SELECT * FROM stats limit 10 ;
+---------------------+-------------+------------+----------+-------+
| timestamp | currenttemp | targettemp | endtime | state |
+---------------------+-------------+------------+----------+-------+
| 2017-04-06 17:58:05 | 19.53 | 40 | 10:00:00 | OFF |
+---------------------+-------------+------------+----------+-------+

MySQL - Select to retrieve last datetime

I've got a table in MySQL:
| period_duration | duration | sample | corner | country | partner | ok_rate
+---------------------+----------+--------+----------+---------+-----------------------+-------------------------
| 2014-12-15 17:00:00 | 3600 | 1 | GRPS_INB | ARG | Charlie | 98 |
| 2014-12-15 17:00:00 | 3600 | 1 | GRPS_INB | DEU | Jack | 90 |
| 2014-12-15 17:00:00 | 3600 | 1 | GRPS_INB | NLD | Will | 100 |
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | ARG | Charlie | 98 |
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | DEU | Jack | 90 |
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | NLD | Will | 100 |
+-----------------+-------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------------------+-------+
| period_duration | datetime | NO | PRI | 0000-00-00 00:00:00 | |
| duration | varchar(6) | YES | | NULL | |
| sample | varchar(2) | YES | | NULL | |
| corner | varchar(10) | YES | | NULL | |
| country | varchar(60) | NO | PRI | | |
| partner | varchar(60) | NO | PRI | | |
| ok_rate | int(8) | YES | | NULL | |
+-----------------+-------------+------+-----+---------------------+-------+
This table increases from hour to hour.
I need a shellscript that will check each line from the last hour and that has an "ok_rate" lower than a given value, and return them to me on a select.
The select should bring country, the partner, and the ok_rate.
Example:
Let's say I want it to be done with <=98%¨on "ok_rate".
My returning rows would be:
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | ARG | Charlie | 98 |
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | DEU | Jack | 90 |
So far, I could only make it bring me the values below 98%, but not those that are also the last datetime that exists:
select country, partner, ok_rate from TABLE where ok_rate <= '98'
But how can I add a WHERE clause the makes it understand I want the last existing datetime that exists on period_duration too?
I mean something like:
SELECT country, partner, ok_rate FROM TABLE WHERE pdp_in_ok_rate <=98 AND (period_duration IS THE LAST ONE)?
This query should return what you want:
SELECT country, partner, ok_rate
FROM TABLE WHERE ok_rate <= 98
AND period_duration = (SELECT MAX(period_duration)
FROM TABLE)
Look in to GROUP BY for more detail because I'm not exactly sure what you want but something like this should help:
SELECT country, partner, ok_rate FROM TABLE
WHERE ok_rate <= '98'
GROUP BY `partner`, `country`
HAVING period_duration = MAX(period_duration);