I need MYSQL query to represent check-in check-out log - mysql

Being a fresher in query writing, I need help at this MySQL scenario.My table has below records:
event_time status
10:01 ON
10:02 ON
10:03 OFF
10:04 ON
10:07 OFF
10:08 ON
10:09 ON
10:11 ON
10:15 OFF
I want to print record as
log_in log_out onCount
10:01 10:03 2
10:04 10:07 1
10:08 10:15 3
Any Suggestion.... ?? or code to get this result set

Related

MySQL - Getting number of days user spent on each status

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.

Count how many times a rows enter time is within the enter and exit times of all other rows

I am looking to estimate a queue length for historical data at the time a record enters the queue. I would like to do this by counting how many of the rows in the data set have an enter time less than the enter time of the record, and an exit time greater than the enter time of the record.
I have created a data set that separates dates and times, which I thought would make it easier to work with, but I am having trouble getting a count of rows for each record in the data set. I have tried doing a simple aggregate count, which works for a single row, but I do not know how to make a query that will do the count for every row in the data set.
For Example I have a data set that looks like this:
RecordID | Enter_Date_Time | Exit_Date_Time
1 2020-09-01 6:00:00 AM 2020-09-02 7:00:00 AM
2 2020-09-01 6:00:00 AM 2020-09-02 8:00:00 AM
3 2020-09-03 4:00:00 AM 2020-09-03 3:00:00 PM
4 2020-09-02 4:00:00 AM 2020-09-04 6:00:00 AM
5 2020-09-02 6:00:00 AM 2020-09-02 8:00:00 AM
6 2020-09-05 6:00:00 AM 2020-09-07 7:00:00 PM
7 2020-09-07 3:00:00 AM 2020-09-07 9:00:00 AM
8 2020-09-07 6:00:00 AM 2020-09-08 8:00:00 AM
9 2020-09-08 6:00:00 AM 2020-09-08 9:00:00 PM
10 2020-09-08 4:00:00 AM 2020-09-09 6:00:00 AM
And I would like it to look like this:
RecordID | Enter_Date_Time | Exit_Date_Time | Queue_Length
1 2020-09-01 1:00:00 AM 2020-09-02 7:00:00 AM 1
2 2020-09-01 6:00:00 AM 2020-09-02 8:00:00 PM 2
3 2020-09-03 4:00:00 AM 2020-09-03 3:00:00 PM 2
4 2020-09-02 4:00:00 AM 2020-09-04 6:00:00 AM 2
5 2020-09-02 6:00:00 AM 2020-09-02 6:00:00 AM 3
6 2020-09-05 6:00:00 AM 2020-09-07 7:00:00 PM 1
7 2020-09-07 3:00:00 AM 2020-09-07 9:00:00 AM 2
8 2020-09-07 6:00:00 AM 2020-09-08 8:00:00 AM 3
9 2020-09-08 6:00:00 AM 2020-09-08 9:00:00 PM 2
10 2020-09-08 4:00:00 AM 2020-09-09 6:00:00 AM 1
My current query looks like this for one single record and manually entering the times for the row:
SELECT COUNT(*)
FROM tbl
WHERE Enter_Date_Time >= '2020-09-02 6:00:00 AM'
AND Exit_Date_Time <= '2020-09-02 6:00:00 AM'
I need a simple operation like this to be done for every row in the data set and have the times in the where clause be the enter time for the record.
Your expertise is greatly appreciated!
One option uses a correlated subquery:
select
t.*,
(
select 1 + count(*)
from mytable t1
where t1.enter_date_time < t.enter_date_time and t1.exit_date_time > t.enter_date_time
) queue_length
from mytable t

How to get particular column data from mysql table?

I have table like this,
tid vid emp_id stop_time dates
----------------------------------------
1 5680 6 01:00 am 2017-05-19
2 5680 6 04:00 am 2017-05-19
3 5680 3 07:00 am 2017-05-19
4 5680 3 05:00 pm 2017-05-19
5 5680 6 08:00 am 2017-05-20
I want the particular value, for above this e.g i need this values 04:00 am and 05:00 pm and 08:00 am. That means i need last enter value of emp_id also particular dates based.
Demo data:
http://sqlfiddle.com/#!9/3f6e59/1
use subquery
select * from third_table
where tid in (select max(tid) from third_table
where dates between '2017-05-19' and '2017-05-20' group by emp_id,dates)

SELECT within a SELECT? Different Data in single report

My goal is to generate a report that will provide me with data to submit to a payroll company.
Our pay periods are the 1st through the 15th and then the 16th through the end of the month and I can easily generate a report that shows how many hours an employee works between those given dates.
My problem is with overtime. Overtime is calculated based on an employees work in a given week. Our week start and end dates are Sunday through Saturday. Here is a specific example of the challenge.
The pay period that ends on 2016-01-31 is part of weeks 3, 4, 5 and 6. It has seven days in week 4 and 5, and only one day in week 3 and 6. I would like to pay (on this particular pay period) any overtime the employee worked in weeks 3, 4 and 5. I will pay them for week 6 overtime in the next pay period once that week is complete.
I need a little help. Specifically a direction to start looking. Would this be a situation where I would embed a SELECT within a SELECT? Since I am operating on two different spins on the same data source ... I am a little baffled.
Anyone have any experience here? Thoughts?
Report for Pay Period Ending 2016-01-31
Employee Hours OT Hr
----------------------- ------- -------
Joe Employee 95.00 1.00
- Week 3 (1 Day) 7.00 1.00
- Week 4 (7 Days) 40.00 0.00
- Week 5 (7 Days) 40.00 0.00
- Week 6 (1 Day) 8.00 0.00
This sample report shows that an employee worked 96 hours over 16 days during the pay period ending 2016-01-31. The one hour of overtime and 7 hours of regular time in week 3 suggests they worked extra on hours in the previous pay period that propelled their week 3 total hours over 40.
Business Rule: Overtime is paid for an employees hours that exceed 40 during a week. Weeks are defined as the time from Sunday to Saturday. Payments are made on Pay Dates. Pay Dates are defined as the 15th and last day of each month. If a Pay Period occurs in the middle of a week. Employees are paid for overtime hours on both side of the pay date as defined above.
Sample Data as Requested
Employee Start End Week PayPeriod Duration
John Employee 2016-01-02 09:23:42 2016-01-02 15:13:43 1 1/15/2016 5.83
John Employee 2016-01-04 09:42:30 2016-01-04 17:58:19 2 1/15/2016 8.26
John Employee 2016-01-05 09:46:04 2016-01-05 13:30:03 2 1/15/2016 3.73
John Employee 2016-01-05 14:03:02 2016-01-05 18:06:34 2 1/15/2016 4.06
John Employee 2016-01-06 10:30:43 2016-01-06 17:14:18 2 1/15/2016 6.73
John Employee 2016-01-07 10:05:22 2016-01-07 13:43:59 2 1/15/2016 3.64
John Employee 2016-01-07 14:14:20 2016-01-07 18:05:50 2 1/15/2016 3.86
John Employee 2016-01-08 09:55:59 2016-01-08 17:47:58 2 1/15/2016 7.87
John Employee 2016-01-11 10:28:22 2016-01-11 17:54:04 3 1/15/2016 7.43
John Employee 2016-01-12 09:33:30 2016-01-12 10:08:43 3 1/15/2016 0.59
John Employee 2016-01-12 10:39:59 2016-01-12 18:29:24 3 1/15/2016 7.82
John Employee 2016-01-13 10:41:16 2016-01-13 13:39:29 3 1/15/2016 2.97
John Employee 2016-01-13 13:39:29 2016-01-13 15:05:05 3 1/15/2016 1.43
John Employee 2016-01-13 15:05:06 2016-01-13 17:25:30 3 1/15/2016 2.34
John Employee 2016-01-14 10:32:28 2016-01-14 14:01:33 3 1/15/2016 3.48
John Employee 2016-01-14 14:20:47 2016-01-14 18:07:42 3 1/15/2016 3.78
John Employee 2016-01-15 09:40:31 2016-01-15 17:19:34 3 1/15/2016 7.65
John Employee 2016-01-16 09:40:31 2016-01-16 17:19:34 3 1/31/2016 7.65
John Employee 2016-01-18 10:01:39 2016-01-18 15:40:43 4 1/31/2016 5.65
John Employee 2016-01-18 15:53:38 2016-01-18 18:38:27 4 1/31/2016 2.75
John Employee 2016-01-19 10:43:24 2016-01-19 18:13:04 4 1/31/2016 7.49
John Employee 2016-01-20 10:38:38 2016-01-20 14:16:09 4 1/31/2016 3.63
John Employee 2016-01-20 14:16:09 2016-01-20 17:55:07 4 1/31/2016 3.65
John Employee 2016-01-21 10:39:31 2016-01-21 18:56:42 4 1/31/2016 8.29
John Employee 2016-01-22 10:57:55 2016-01-22 15:44:03 4 1/31/2016 4.77
John Employee 2016-01-22 15:57:54 2016-01-22 18:11:28 4 1/31/2016 2.23
John Employee 2016-01-25 10:08:57 2016-01-25 19:14:21 5 1/31/2016 9.09
John Employee 2016-01-26 10:45:35 2016-01-26 14:17:13 5 1/31/2016 3.53
John Employee 2016-01-26 14:40:51 2016-01-26 18:31:56 5 1/31/2016 3.85
John Employee 2016-01-27 09:53:33 2016-01-27 18:05:40 5 1/31/2016 8.20
John Employee 2016-01-28 10:36:57 2016-01-28 16:28:16 5 1/31/2016 5.86
John Employee 2016-01-28 16:43:20 2016-01-28 19:42:17 5 1/31/2016 2.98
John Employee 2016-01-31 10:00:40 2016-01-31 16:27:46 6 1/31/2016 6.45
John Employee 2016-02-01 10:45:42 2016-02-01 14:04:03 6 2/15/2016 3.31
John Employee 2016-02-01 14:15:06 2016-02-01 17:45:05 6 2/15/2016 3.50
John Employee 2016-02-01 17:45:05 2016-02-01 19:01:34 6 2/15/2016 1.27
John Employee 2016-02-02 11:03:49 2016-02-02 17:40:21 6 2/15/2016 6.61
John Employee 2016-02-03 11:08:06 2016-02-03 17:15:38 6 2/15/2016 6.13
John Employee 2016-02-04 11:20:59 2016-02-04 17:27:15 6 2/15/2016 6.10
John Employee 2016-02-04 17:27:15 2016-02-04 20:19:34 6 2/15/2016 2.87
John Employee 2016-02-05 10:47:57 2016-02-05 17:53:54 6 2/15/2016 7.10
John Employee 2016-02-08 10:51:45 2016-02-08 15:15:28 7 2/15/2016 4.40
John Employee 2016-02-08 15:34:52 2016-02-08 17:30:54 7 2/15/2016 1.93
John Employee 2016-02-09 11:01:09 2016-02-09 13:11:02 7 2/15/2016 2.16
John Employee 2016-02-09 13:11:02 2016-02-09 17:38:03 7 2/15/2016 4.45
John Employee 2016-02-09 17:38:03 2016-02-09 18:34:20 7 2/15/2016 0.94
John Employee 2016-02-10 10:43:39 2016-02-10 11:25:38 7 2/15/2016 0.70
John Employee 2016-02-10 11:25:38 2016-02-10 17:58:11 7 2/15/2016 6.54
John Employee 2016-02-11 10:16:30 2016-02-11 14:06:35 7 2/15/2016 3.83
John Employee 2016-02-11 14:30:17 2016-02-11 17:25:23 7 2/15/2016 2.92
John Employee 2016-02-12 10:46:50 2016-02-12 17:46:38 7 2/15/2016 7.00
I need to pay 5.15 hours of overtime in PayPeriod 2016-01-15 because he did not go over 40 until after the 2015-01-15 pay period closed.
If the employee had crossed over 40 hours before the 2016-01-15 pay period closed, I would have needed to pay overtime on both the 2016-01-15 and the 2016-01-31 pay periods for week three hours.
Here's my thought on overtime calculation:
you'll start checking the start date for the period, which day is it? If it is not Sunday, that means you need to pay some overtime for earlier dates? Well, for how many days? You'll always start from the sunday of that week for calculating the overtime for that week. Some useful mySql functions here are: DAYOFWEEK() and DATE_ADD()
Then you'll continue until the end date for that period is reached/passed, and you'll calculate the overtime for each week (sunday-saturday). If a saturday is passed your end date for the payroll period, you'll just skip that week for your overtime calculation.

How to get available time for doctor from todays appointments?

I am working on a project in a company. I am trying to solve this query but I could not.
My tables are:
Appointments:
doctorId patientId patientName fromDateTime toDateTime
-------- --------- ----------- --------------------- ---------------------
56 1 fghfgh 3/23/2012 12:15:00 PM 3/23/2012 01:15:00 PM
56 2 asdadf 3/23/2012 01:15:00 PM 3/23/2012 02:15:00 PM
56 3 werwr 3/23/2012 09:15:00 AM 3/23/2012 10:15:00 AM
57 4 uiyui 3/23/2012 09:15:00 AM 3/23/2012 10:15:00 AM
57 5 asdad 3/23/2012 01:15:00 PM 3/23/2012 02:15:00 PM
This is my timeSchedule table:
id startTime endTime
-- ------------ ------------
1 08:00:00.000 09:00:00.000
2 09:00:00.000 10:00:00.000
3 11:00:00.000 12:00:00.000
4 12:00:00.000 13:00:00.000
5 13:00:00.000 14:00:00.000
6 14:00:00.000 15:00:00.000
7 15:00:00.000 16:00:00.000
Actually there are more values but I think these are enough to solve the problem.
I am comparing patient appointments with this timeSchedule table.
Now suppose if I pass parameter doctorId as 56 and consider today is 23 March then output should be like this:
id startTime endTime
-- --------- --------
1 08:00 AM 09:00 AM
3 11:00 AM 12:00 PM
6 02:00 PM 03:00 PM
7 03:00 PM 04:00 PM
How can I achieve the above result?
Assuming that timeSchedule.startTime and timeSchedule.endTime are both Time data types then it would be something like this...: (if not, you could cast as such).
DECLARE #pDoctorID Int = 56
DECLARE #pDate Date = '3/23/2012'
SELECT * FROM timeSchedule WHERE
NOT Exists (
SELECT doctorid FROM Appointments
WHERE doctorid = #pDoctorID AND
CAST(fromDatetime as Date) = #pDate AND
(
(CAST(fromDatetime as Time) >= timeSchedule.startTime AND
CAST(fromDatetime as Time) <= timeSchedule.endTime)
OR
(CAST(toDatetime as Time) >= timeSchedule.startTime AND
CAST(toDatetime as Time) <= timeSchedule.endTime)
OR
(CAST(toDatetime as Time) <= timeSchedule.startTime AND
CAST(fromDatetime as Time) >= timeSchedule.endTime)
)
)
Which with your sample data returns this:
1 | 08:00:00.00 | 09:00:00.00
4 | 11:00:00.00 | 12:00:00.00
8 | 15:00:00.00 | 16:00:00.00
In essence the query is saying give me any appointment for this doctor where existing appoints do not start or end between the time frames, or start before and end after any of the time slots defined by the timeSchedule table.
Formatting the return times is also a simple matter. See the table in this link for all your options.