MySQL - Getting number of days user spent on each status - mysql

I have been trying to extract the number of days a particular user spent on each status in a month from the MySQL database table. The data is saved in log format which makes it a bit hard to work with. For e.g. I need to calculate the number of days the user 488 spent on each status in the month of June 2022 only.
user_id old_status new_status modified_on
488 3 10 31/05/2022 10:03
488 10 5 01/06/2022 13:05
488 5 16 07/06/2022 16:06
488 16 2 09/06/2022 08:26
488 2 6 30/06/2022 13:51
488 6 2 07/07/2022 09:44
488 2 6 08/08/2022 13:25
488 6 1 15/08/2022 10:37
488 1 11 02/09/2022 13:48
488 11 2 03/10/2022 07:26
488 2 10 10/10/2022 10:17
488 10 6 25/01/2023 17:50
488 6 1 01/02/2023 13:46
The output should look like this:
The output should look like:
user status Days
488 5 6
488 16 2
488 2 21
I tried multiple ways to join the same table with itself in order to find the solution but no luck. Any help will be appreciated.

here is what I think you should do, first join the old_status field in the log table with the status table then use the DATEDIFF function to subtract modified_on(log table ) from created_at(or any other field in status that stores creation time) you can filter results using where clause to get certain users on certain dates
this query might help (i don't know the structure of your tables so if there is something wrong edit it to suit your needs)
SELECT *,DATEDIFF(log.modified_at,st.created_at) AS spent_time_on_staus
FROM log_status AS log JOIN status AS st ON st.id=log.old_status
WHERE log.user_id=488 AND EXTRACT(MONTH FROM st.created_at) = 6

This is a suggestion to get you started. It will not get you all the way (since there are several status changes to and from the same status...)
SELECT
shfrom.userid,
shfrom.new_status as statusName,
shfrom.modified_on as fromdate,
shto.modified_on as todate,
DATEDIFF(shto.modified_on, shfrom.modified_on) as days_spent_in_status
FROM
status_history as shfrom
INNER JOIN status_history as shto
ON shfrom.userid = shto.userid and shfrom.new_status = shto.old_status
WHERE
shfrom.modified_on < shto.modified_on
;
I created a table based on your question and put in the data you provided, in mysql format:
create table status_history(
userid int,
old_status int,
new_status int,
modified_on datetime
);
insert into status_history values
(488, 3,10, '2022-05-31 10:03'),
(488,10, 5, '2022-06-01 13:05'),
(488, 5,16, '2022-06-07 16:06'),
(488,16, 2, '2022-06-09 08:26'),
(488, 2, 6, '2022-06-30 13:51'),
(488, 6, 2, '2022-07-07 09:44'),
(488, 2, 6, '2022-08-08 13:25'),
(488, 6, 1, '2022-08-15 10:37'),
(488, 1,11, '2022-09-02 13:48'),
(488,11, 2, '2022-10-03 07:26'),
(488, 2,10, '2022-10-10 10:17'),
(488,10, 6, '2023-01-25 17:50'),
(488, 6, 1, '2023-02-01 13:46');
this produces this result, where the duration is the time spent:
userid
statusName
fromdate
todate
days_spent_in_status
488
10
2022-05-31 10:03:00
2022-06-01 13:05:00
1
488
5
2022-06-01 13:05:00
2022-06-07 16:06:00
6
488
16
2022-06-07 16:06:00
2022-06-09 08:26:00
2
488
2
2022-06-09 08:26:00
2022-06-30 13:51:00
21
488
6
2022-06-30 13:51:00
2022-07-07 09:44:00
7
488
2
2022-06-09 08:26:00
2022-08-08 13:25:00
60
488
2
2022-07-07 09:44:00
2022-08-08 13:25:00
32
488
6
2022-06-30 13:51:00
2022-08-15 10:37:00
46
488
6
2022-08-08 13:25:00
2022-08-15 10:37:00
7
488
1
2022-08-15 10:37:00
2022-09-02 13:48:00
18
488
11
2022-09-02 13:48:00
2022-10-03 07:26:00
31
488
2
2022-06-09 08:26:00
2022-10-10 10:17:00
123
488
2
2022-07-07 09:44:00
2022-10-10 10:17:00
95
488
2
2022-10-03 07:26:00
2022-10-10 10:17:00
7
488
10
2022-05-31 10:03:00
2023-01-25 17:50:00
239
488
10
2022-10-10 10:17:00
2023-01-25 17:50:00
107
488
6
2022-06-30 13:51:00
2023-02-01 13:46:00
216
488
6
2022-08-08 13:25:00
2023-02-01 13:46:00
177
488
6
2023-01-25 17:50:00
2023-02-01 13:46:00
7
You still need to filter out the ones that are capturing an early status change with a later status change. I hope it gets you started.

Related

Query: Count of issues for specific test (snapshot of point in time)

I am trying to query a count of issues of a test that happened in the past. As a background, every year a test is done. A record is created for each "Issue" that comes up in each test. One test can have 0 to many issues. After the test is complete, those issues can be closed overtime when they're no longer issues. Each issue has a "current" status. There is also a table for tracking status changes on issues, like an audit log. When the next year comes around, the test would include any previous open issues and open additional issues. What is the correct query for finding how many issues are open in a specific test from year to year?
I.e:
2018 had 9 issues. 1 closed overtime.
2019 had 3 new issues plus the 8 still open from 2018.
Expected queries result to show 9 issues for 2018 and 11 issues for 2019.
The query below is what I have so far.
The relation of the tables are as follows.
Engagements - Has one application
Issues - One application can have many issues
Status Change - One issue can have many status changes
SELECT *
COUNT(*) as totalissues,
SUM(CASE WHEN issues.issue_type IN('EAPT','ENPT','ENVS') THEN 1 ELSE 0
end) AS externalissues,
SUM(CASE WHEN issues.issue_type IN('IAPT','INPT','INVS') THEN 1 ELSE 0
end) AS internalissues
FROM engagements
LEFT OUTER JOIN issues ON engagements.application_id = issues.application_id
LEFT OUTER JOIN status_change sc1 ON issues.id = sc1.issue_id AND issues.engagement_id != engagements.engagement_id AND date(sc1.change_date) < date(engagements.end_date)
WHERE
engagements.engagement_id = 'APT_ItemProcessingOutsourcing_DLM_2018_07'
AND (
sc1.id is null
or (
sc1.id = (
SELECT max(sc2.id)
FROM engagements e2
LEFT OUTER JOIN issues i2 ON e2.application_id = i2.application_id
LEFT OUTER JOIN status_change sc2 ON i2.id = sc2.issue_id
AND date(sc2.change_date) < date(e2.end_date)
WHERE
sc1.issue_id = sc2.issue_id
AND sc2.change_date = (
SELECT max(sc3.change_date)
FROM status_change sc3
WHERE sc3.issue_id = sc2.issue_id
AND sc3.change_date <= date(e2.end_date)
)
)
)
AND sc1.new_status not in(4,8,9,10)
);
This query has a count of 6 issues, I am expecting 9. Please let me know if you need more information.
Status change Table
id old_status new_status change_date issue_id user_id comment_id
40748721 10 1 7/18/2017 15:09 14440592 64 NULL
67384812 1 3 7/26/2018 16:43 14440592 26 13023597
67384814 7 4 7/26/2018 16:44 14440592 26 13023599
67384813 3 7 7/26/2018 16:43 14440592 26 13023598
40748722 10 1 7/18/2017 15:09 14440593 64 NULL
40748724 10 1 7/18/2017 15:09 14440595 64 NULL
40748725 10 1 7/18/2017 15:09 14440596 64 NULL
40748723 10 1 7/18/2017 15:09 14440594 64 NULL
67383070 1 3 7/26/2018 14:15 14440594 26 13023588
67383078 7 4 7/26/2018 14:16 14440594 26 13023590
67383074 3 7 7/26/2018 14:15 14440594 26 13023589
40748726 10 1 7/18/2017 15:09 14440597 64 NULL
40748727 10 1 7/18/2017 15:09 14440598 64 NULL
40748728 10 1 7/18/2017 15:09 14440599 64 NULL
40748729 10 1 7/18/2017 15:09 14440600 64 NULL
71206458 10 1 8/27/2018 11:46 23900484 26 NULL
71206459 10 1 8/27/2018 11:46 23900485 26 NULL
112852911 10 1 5/24/2019 5:07 800002498 99 NULL
112852912 10 1 5/24/2019 5:07 800002499 99 NULL
112852913 10 1 5/24/2019 5:07 800002500 99 NULL
112852914 10 1 5/24/2019 5:07 800003019 99 NULL
92704214 3 2 3/22/2019 9:39 14440593 80 16533839
92704217 3 2 3/22/2019 9:39 14440595 80 16533842
92704218 3 2 3/22/2019 9:39 14440596 80 16533843
92704219 3 2 3/22/2019 9:39 14440597 80 16533844
92704215 3 2 3/22/2019 9:39 14440598 80 16533840
92704216 3 2 3/22/2019 9:39 14440599 80 16533841
92704220 3 2 3/22/2019 9:39 14440600 80 16533845
93598047 3 2 3/24/2019 9:51 23900484 80 16548757
77165368 3 2 10/22/2018 14:28 23900485 64 14221198
93598048 3 2 3/24/2019 9:51 23900485 80 16548758
92654993 1 3 3/21/2019 1:00 14440593 1 16531378
92654994 1 3 3/21/2019 1:00 14440595 1 16531379
121160006 2 3 6/20/2019 1:00 14440595 1 17411641
92654995 1 3 3/21/2019 1:00 14440596 1 16531380
121160007 2 3 6/20/2019 1:00 14440596 1 17411642
92654996 1 3 3/21/2019 1:00 14440597 1 16531381
92654997 1 3 3/21/2019 1:00 14440598 1 16531382
92654998 1 3 3/21/2019 1:00 14440599 1 16531383
102075451 2 3 4/24/2019 8:53 14440599 99 16875917
92654999 1 3 3/21/2019 1:00 14440600 1 16531384
92655000 1 3 3/21/2019 1:00 23900484 1 16531385
102075453 2 3 4/24/2019 8:55 23900484 99 16875919
75968834 1 3 10/13/2018 1:00 23900485 1 14157115
92655001 2 3 3/21/2019 1:00 23900485 1 16531386
122784894 3 4 6/26/2019 7:40 14440595 99 17548826
122784893 3 4 6/26/2019 7:40 14440596 99 17548825
112836464 7 4 5/23/2019 23:51 14440599 80 17238673
112836465 7 4 5/23/2019 23:52 23900484 80 17238674
102075452 3 7 4/24/2019 8:54 14440599 99 16875918
102075455 3 7 4/24/2019 8:56 23900484 99 16875921
Engagement example
engagement_id application_id start_date end_date
APT_ItemProcessingOutsourcing_DLM_2018_07 735 7/16/2018 7/26/2018
Issues example
id created issue_type status_id application_id engagement_id
14440592 2017-07-18 15:09:09 EAPT 4 735 APT_ItemProcessingOutsourcing_DLM_2017_03
14440593 2017-07-18 15:09:09 EAPT 2 735 APT_ItemProcessingOutsourcing_DLM_2017_03
14440594 2017-07-18 15:09:10 EAPT 4 735 APT_ItemProcessingOutsourcing_DLM_2017_03
14440595 2017-07-18 15:09:10 EAPT 4 735 APT_ItemProcessingOutsourcing_DLM_2017_03
14440596 2017-07-18 15:09:10 EAPT 4 735 APT_ItemProcessingOutsourcing_DLM_2017_03
14440597 2017-07-18 15:09:10 EAPT 2 735 APT_ItemProcessingOutsourcing_DLM_2017_03
14440598 2017-07-18 15:09:10 EAPT 2 735 APT_ItemProcessingOutsourcing_DLM_2017_03
14440599 2017-07-18 15:09:10 EAPT 4 735 APT_ItemProcessingOutsourcing_DLM_2017_03
14440600 2017-07-18 15:09:10 EAPT 2 735 APT_ItemProcessingOutsourcing_DLM_2017_03
23900484 2018-08-27 11:46:38 EAPT 4 735 APT_ItemProcessingOutsourcing_DLM_2018_07
23900485 2018-08-27 11:46:38 EAPT 2 735 APT_ItemProcessingOutsourcing_DLM_2018_07
800002498 2019-05-24 05:07:28 EAPT 1 735 APT_ItemProcessingOutsourcing_DLM_2019_04
800002499 2019-05-24 05:07:28 EAPT 1 735 APT_ItemProcessingOutsourcing_DLM_2019_04
800002500 2019-05-24 05:07:28 EAPT 1 735 APT_ItemProcessingOutsourcing_DLM_2019_04
800003019 2019-05-24 05:07:28 EAPT 1 735 APT_ItemProcessingOutsourcing_DLM_2019_04

Calculate the percentage of success of each measurement values in SQL

I have 3 database tables with sample data given below
Meas_id - integer(Foreign keyed to Measurement.meas_id)
Tool_id - integer(Foreign keyed to Events.Machine_id)
Processdate- Timestamp with timezone (UTC)
CreatedDate- Timestamp with timezone (UTC)
Readings
Meas_id Tool_id Status Processdate
1 13 Completed 2016-01-01 01:34:11
1 28 Failed 2016-01-01 08:37:11
1 54 Failed 2016-01-02 16:04:12
1 32 Completed 2016-01-04 07:13:11
1 39 Completed 2016-01-04 14:14:14
1 12 Completed 2016-01-05 22:10:09
1 9 Completed 2015-12-28 13:11:07
1 17 Completed 2016-01-25 13:14:11
1 27 Completed 2016-01-15 14:15:16
1 31 Failed 2016-01-07 16:08:04
2 113 Completed 2016-01-01 01:34:11
2 128 Failed 2016-01-01 08:37:11
2 154 Failed 2016-01-02 16:04:12
2 132 Completed 2016-01-04 07:13:11
2 139 Completed 2016-01-04 14:14:14
2 112 Completed 2016-01-05 22:10:09
2 90 Completed 2015-12-28 13:11:07
2 117 Completed 2016-01-25 13:14:11
2 127 Completed 2016-01-15 14:15:16
2 131 Failed 2016-01-07 16:08:04
Events
Meas_id Machine_id Event_Name CreatedDate
1 13 Success 2015-12-27 01:34:11
1 17 Error 2015-12-27 08:37:11
1 28 Success 2015-12-27 16:04:12
1 9 Success 2015-12-28 07:13:11
1 54 Success 2015-12-28 14:14:14
1 31 Error 2015-12-28 22:10:09
1 32 Success 2015-12-29 13:11:07
1 39 Success 2015-12-29 13:14:11
1 12 Success 2015-12-31 14:15:16
1 27 Success 2016-01-01 16:08:04
2 113 Success 2015-12-27 01:34:11
2 117 Error 2015-12-27 08:37:11
2 128 Success 2015-12-27 16:04:12
2 90 Success 2015-12-28 07:13:11
2 154 Success 2015-12-28 14:14:14
2 131 Error 2015-12-28 22:10:09
2 132 Success 2015-12-29 13:11:07
2 139 Success 2015-12-29 13:14:11
2 112 Success 2015-12-31 14:15:16
2 127 Success 2016-01-01 16:08:04
Mesurement
Meas_id Meas_name
1 Length
2 Breadth
For each measurement ‘length’ and ‘breadth’ and each day of the week, I am trying to calculate the percentage of success in the first week of 2016 for all completed measurements of tools/machines within 168 hours of thier creation date.
My Desired Output is
Measurement DayofTheWeek PercentageSuccess
Length 1 50
Length 2 0
Length 3 0
Length 4 100
Length 5 100
Length 6 0
Length 7 0
Breadth 1 50
Breadth 2 0
Breadth 3 0
Breadth 4 100
Breadth 5 100
Breadth 6 0
Breadth 7 0
I tried doing it this way but certainly missing some logic and its not working.
Select m.Meas_name,
datepart(dd, Processdate) as DayofTheWeek,
(Count(m.Meas_name)* 100 / (Select Count(Event_Name) From Events where Event_Name = 'Success')) as PercentageSuccess
FROM Readings r JOIN
Measurements m
ON r.Meas_id = m.Meas_id
JOIN Events e
ON e.Meas_id = m.Meas_id
WHERE m.Meas_name IN ('Length', 'Breadth') AND
r.Status = 'Completed' AND
e.CreatedDate >= DATEADD(hh, -168, GETDATE())
GROUP BY m.Meas_name, datepart(dd, Processdate);
Kindly provide inputs on an optimized way of achieving it.
Nice I got downvoted for a correct answer probably because my answer wasn't very clear it is kind of hard to explain so here is an edit aimed at your comment and the downvoter (whom I think was just retaliating).
Anyway, Your joining of 3 tables while valid replicates the data in your events table. Due to that the way you are counting the records will always be exaggerated and incorrect. your calculation for percentage is also happens to be backwards.
On the join it looks like you are just missing the use of the Tool_id in your join. You could try something like the following:
SELECT
m.Meas_name
,DAYOFWEEK(r.ProcessDate) as DayOfTheWeek
,(COUNT(CASE WHEN e.Event_Name = 'Success' tHEN e.Meas_id END)/(COUNT(e.Meas_id) * 1.0)) * 100 as PercentageSuccess
FROM
Measurements m
INNER JOIN Events e
ON m.Meas_id = e.Meas_id
INNER JOIN Readings r
ON e.Meas_id = r.Meas_id
AND e.Machine_id = r.Tool_id
AND r.Status = 'Completed'
AND r.ProcessDate BETWEEN '2016-01-01' AND '2016-01-07'
WHERE
m.Meas_name IN ('Length','Breadth')
GROUP BY
m.Meas_name
,DAYOFWEEK(r.ProcessDate)
Note this is written for mysql because that is what is tagged in you post. if you actually want sql-server as your syntax suggests let me know. Also, I am guessing that you a really want to filter by processdate but if you want to filter by Event.CreateDate then put that in the ON condition of the Events join.

Count number of clients in a routine in Mysql

Hi I have a database in mysql and php use to read the data, I have a table called payments where insert payments routines that make customers then are three tables "payments, routines and customers," Now the issue is that I want to load the number of customers using routine id "3", I got it resolved but a detail escapes me, I need the client ID is not the same on the counter and thus can not be counted twice for the same customer in a rut when you have two payments that routine.
The statement that I have is:
select r.name_routine, count(p.id_routine)
from payments p,routines r,customers c
where p.id_client=c.id_client
and p.id_routine=r.id_routine
and p.id_routine='3'
Data set, in spanish:
id_pago monto activo fecha_pago fecha_vencimiento observacion id_cliente id_rutina id_oferta
17 300 1 2016-02-24 2016-03-24 Ninguna 11 3 NULL
13 450 1 2016-02-05 2016-07-05 Ninguna 8 NULL 8
16 270 1 2016-02-05 2016-03-05 Ninguna 7 5 NULL
11 490 1 2016-02-04 2016-04-04 Ninguna 8 NULL 5
15 300 0 2016-02-04 2015-03-04 Ninguna 11 3 NULL
9 330 1 2016-02-03 2016-03-03 Ninguna 11 10 NULL
12 400 1 2016-02-03 2016-05-03 Ninguna 10 NULL 7
10 500 1 2016-02-02 2016-06-02 Ninguna 10 NULL 4
14 420 1 2016-02-02 2016-05-02 Ninguna 8 NULL 9
5 250 0 2016-01-18 2016-02-18 Ninguna 5 7 NULL
8 320 0 2016-01-05 2016-02-05 Ninguna 9 9 NULL
7 250 0 2016-01-03 2016-02-03 Ninguna 7 7 NULL
6 300 0 2016-01-02 2016-02-02 Ninguna 6 6 NULL
2 520 1 2015-10-18 2016-03-18 Ninguna 2 NULL 2
3 290 0 2015-10-18 2015-11-18 Ninguna 3 4 NULL
4 550 0 2015-10-18 2016-01-18 Ninguna 4 NULL 3
In this table you can see that the routine "3" is used 2 times by the same customer (id_client 11), then my query should return the routine is used 1 time and not two, that's what I want to tell all clients that are in routine "3"
Try using distinct but returns the same result, how could you do this?
This should work
SELECT groupedTable.name_routine, COUNT(groupedTable.numbers) FROM
(
SELECT r.name_routine, count(p.id_routine) as numbers
FROM payments p,routines r,customers c
where p.id_client=c.id_client
and p.id_routine=r.id_routine
and p.id_routine='3'
GROUP BY p.id_client) as groupedTable
This should work:
select r.name_routine, count(distinct p.id_cliente)
from payments p,routines r,customers c
where p.id_client=c.id_client
and p.id_routine=r.id_routine
and p.id_routine='3'

Need help in an Sql Query

I have a fee Table. Whenever a student paying fee it will store in this table.
feeid student_id paid_date received_amount balance_amount next_due_date
3 1 2015-11-07 1000 15000 2015-11-01
5 2 2015-11-07 2000 14000 2015-11-02
9 3 2015-11-07 30000 15000 2015-11-07
11 1 2015-11-07 1000 14000 2015-07-11
12 4 2015-11-07 1000 40000 2015-11-07
13 4 2015-11-07 1000 39000 2015-12-01
14 3 2015-11-07 1000 14000 2015-11-30
15 5 2015-11-09 1000 25000 2015-11-09
16 1 2015-11-09 5000 9000 2015-11-30
17 2 2015-11-09 1000 13000 2015-11-15
18 6 2015-11-10 1000 20000 2015-11-10
19 1 2015-11-11 1000 8000 2015-11-11
20 4 2015-11-11 1000 38000 2015-11-11
21 7 2015-11-11 1000 24000 2015-11-11
22 8 2015-11-11 1000 19500 2015-11-11
23 1 2015-11-14 1000 7000 2015-11-16
So there are more than 1 entries for a single single.I need every students fee details(only last paid details)
Here's one way:
SELECT *
FROM table t1
WHERE paid_date=(SELECT MAX(t2.paid_date)
FROM table t2
WHERE t1.student_id = t2.student_id);
First get all the unique student ids.
After that in a loop
SELECT * FROM table_name WHERE student_id = studentIdFromLoop ORDER BY feeid DESC LIMIT 1
This will give you the last fee record of the every student.

mySQL AVG a field with a range of dates on the same table

I have a table
date d_id r_id p_id q_sold onhand
2012-10-10 5 1 3025 3 10
2012-10-10 5 1 3022 12 20
2012-10-10 5 1 3023 15 33
2012-10-11 5 1 3025 3 10
2012-10-11 5 1 3022 12 20
2012-10-11 5 1 3023 15 33
2012-10-12 5 1 3025 3 10
2012-10-12 5 1 3022 12 20
2012-10-12 5 1 3023 15 33
2012-10-13 5 1 3025 3 10
2012-10-13 5 1 3022 12 20
2012-10-13 5 1 3023 15 33
2012-10-14 5 1 3025 3 10
2012-10-14 5 1 3022 12 10
2012-10-14 5 1 3023 15 33
2012-10-15 5 1 3025 3 5
2012-10-15 5 1 3022 12 5
2012-10-15 5 1 3023 15 33
I would like to get the result of the q_sold divided by average of the onhand over a 5 day period, while displaying the other data for a specific date like the 2012-10-15.
I create a query
set #stdate = '2012-10-10';
set #endate = '2012-10-15';
SELECT date, d_id,r_id,p_id,q_sold,onhand,qty_sold/AVG(qty_onhand)
FROM stp_vwsales_info_tots
WHERE date BETWEEN #stdate and #endate and d_id=5
GROUP BY d_id,r_id,p_id
But the result being showed is incorrect, it displays the data for the 2012-10-10 instead of 2010-10-15
date d_id r_id p_id q_sold onhand avg
2012-10-10 5 1 3022 12 20 0.7579
2012-10-10 5 1 3023 15 33 0.4545
2012-10-10 5 1 3025 3 10 0.3273
Can anyone help?
Use your #stdate and #endate as DATE(#stdate/#endate) or DATE_FORMAT(#stdate/#endate,'%Y-%m-%d') otherwise you have to convert #stdate/#endate from string to date through MySQL
i think what your looking for is something called a simple moving average.
to calculate this you'll need to use an inline subquery - so performance won't be the best.
assuming you want to calculate the average over the previous 5 day period, try something like this:
SELECT
date, d_id, r_id, p_id, q_sold, onhand,
( SELECT q_sold/AVG(t2.onhand)
FROM stp_vwsales_info_tots AS t2
WHERE p_id=t1.p_id AND DATEDIFF(t1.date, t2.date) BETWEEN 0 AND 4
) AS 'moving_avg'
FROM stp_vwsales_info_tots AS t1
GROUP BY t1.p_id,t1.date
order by t1.date;