mysql counting in a particular time period - mysql

I am a newbie in mysql, and i encounter a difficult problem for me.
I have a table storing some room booking information
room_id
booking_start_time
booking_end_time
eg.
room_id | booking_start_time | booking_end_time<br>
1 | 2012-01-01 09:00 | 2012-01-01 11:00
1 | 2012-01-02 09:00 | 2012-01-02 10:00
1 | 2012-01-03 08:00 | 2012-01-03 10:00
2 | 2012-01-01 08:00 | 2012-01-01 10:00
3 | 2012-01-01 08:00 | 2012-01-01 09:00
And i have to do a report to extract the utilization of a room in a month, that is the number of hours used in a particular period of time
and the format is like the following
room 1| room 2
09:00 -10:00|
10:00 -11:00|
My question is that how can count the record, if the booking time is across a number of hours like from 9:00 -11:00, but i have to mark 1 hour in the period 09:00 to 10:00 and another 1 hour in the period 10:00 to 11:00.
I really struggle about it.
Your replies are really appreciated.
Thanks a lot.

Take a look at the MySQL Date Time Functions. Particularly, TIME_DIFF().
In your case, do a TIME_DIFF() for your *booking_time* columns. Combined with a GROUP BY for room_id, you could easily SUM() these for each room in a month.
I recognize that this answer isn't comprehensive. I'm encouraging you to learn these functions.

Related

How to add hours matching a mysql query?

Data (Table name: T1):
Teacher
Subject
Day
Hour
Albert
Blue
Wednesday
10:00
Albert
Blue
Wednesday
12:00
Brandon
Red
Tuesday
09:00
Brandon
Red
Tuesday
11:00
Albert
Cyan
Monday
08:30
Albert
Cyan
Monday
10:30
Claudia
Gray
Thursday
08:00
Claudia
Gray
Thursday
10:00
Albert
Pink
Friday
13:00
Albert
Pink
Friday
14:30
Martha
Green
Wednesday
12:00
Martha
Green
Wednesday
14:00
Albert
Yellow
Friday
11:00
Albert
Yellow
Friday
12:30
As it can be seen, there is a record for the starting hour of a Subject and another for the finishing time of the same Subject (data comes like that).
What I intend to know is the weekly amount of hours dedicated to classes by a specific teacher, let's say for "Albert".
Query:
$result = mysqli_query($link, "SELECT SUBTIME(max(Hour), min(Hour)) AS TeachTime, Subject FROM T1 WHERE Teachers LIKE '%Albert%' GROUP BY Subject ORDER BY Subject ASC") or die(mysqli_error($link));
if (mysqli_num_rows($result)!==0) {
echo "Weekly teaching time: ";
while($row = mysqli_fetch_array($result)){
echo $row['TeachTime']." Hrs. ";
}
}
Output:
Weekly teaching time: 02:00 Hrs. 02:00 Hrs. 01:30 Hrs. 01:30 Hrs.
Desired output:
Weekly teaching time: 07:00 Hrs.
As you can see, I don't know how to perform the addition of every resulting amount of hours. How can I achieve that?
I have also tried GROUP BY Teachers but results are weird... not the addition result.
You know how to get this:
mysql> select teacher, day, min(hour), max(hour)
from T1 where teacher = 'Albert' group by teacher, day;
+---------+-----------+-----------+-----------+
| teacher | day | min(hour) | max(hour) |
+---------+-----------+-----------+-----------+
| Albert | Wednesday | 10:00:00 | 12:00:00 |
| Albert | Monday | 08:30:00 | 10:30:00 |
| Albert | Friday | 11:00:00 | 14:30:00 |
+---------+-----------+-----------+-----------+
And you can use TIMESTAMPDIFF() to calculate the minutes:
mysql> select teacher, day,
timestampdiff(minute, min(hour), max(hour)) as minutes
from T1 where teacher = 'Albert' group by teacher, day;
+---------+-----------+---------+
| teacher | day | minutes |
+---------+-----------+---------+
| Albert | Wednesday | 120 |
| Albert | Monday | 120 |
| Albert | Friday | 210 |
+---------+-----------+---------+
Now wrap that as a subquery in another aggregation query:
mysql> select teacher, sum(minutes) as total_minutes
from (
select teacher, day,
timestampdiff(minute, min(hour), max(hour)) as minutes
from T1 where teacher = 'Albert' group by teacher, day) as t
group by teacher;
+---------+---------------+
| teacher | total_minutes |
+---------+---------------+
| Albert | 450 |
+---------+---------------+
This is the code I end up using thanks to the guidance of Bill Karwin and some more research:
$result = mysqli_query($link, "SELECT *,
SEC_TO_TIME(SUM(TIME_TO_SEC(WeekTime))) AS ProfTime FROM
(SELECT *,
SUBTIME(max(Hour), min(Hour)) AS WeekTime FROM T1
WHERE Teacher LIKE '%Albert%' GROUP BY Teacher, Subject) AS C")
or die(mysqli_error($link));
if (mysqli_num_rows($result)!==0) {
echo "Weekly teaching time: ";
while($row = mysqli_fetch_array($result)){
echo date('H:i', strtotime($row['ProfTime']))." Hrs. <br>";
}}
Bill's answer had made me realize that you can query results from an embedded query, e.g.:
Query2 over results of (Query1 over data)
Then, as results of query1 were in time format (HH:MM), I should get a total of the addition of all the instances retrieved, i.e., 01:00 + 02:00 + 01:30 = 04:30
The addition has to be performed in query2 and I have found on tutorialspoint that the query SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(Time))) AS TotalTime does that.
Finally, as the result comes in the the format HH:MM:SS and I only need HH:MM I applied a php convertion to the output: date('H:i', strtotime($row['TotalTime'])).

Get End Time by Adding Number of Minutes in Start Time Keeping in mind the working hours

I have database table in which I have daily working hours of office.
What I need is to get End Time by Adding Number of minutes in Start Time keeping in mind the office hours. The working hours are from 09:00 to 17:30
I will be thankful if some one could help me to write query in mysql so that I could calculate end time.
my Sample Table is
+------------------+------------------+
| starttime | endtime |
+------------------+------------------+
| 2017-01-01 00:00 | 2017-01-01 00:00 |
| 2017-01-02 09:00 | 2017-01-02 17:30 |
| 2017-01-03 09:00 | 2017-01-03 17:30 |
| 2017-01-04 09:00 | 2017-01-04 17:30 |
| 2017-01-05 09:00 | 2017-01-05 17:30 |
| 2017-01-06 09:00 | 2017-01-06 17:30 |
| 2017-01-07 09:00 | 2017-01-07 14:30 |
| 2017-01-08 00:00 | 2017-01-08 00:00 |
| 2017-01-09 09:00 | 2017-01-09 17:30 |
+------------------+------------------+
Input time : 2017-01-02 16:52
adding minutes: 300
required time : 2017-01-03 12:22
If I understand clearly, you want:
SELECT CONCAT(FLOOR((540 + t.time)/60),'h ', MOD(540 + t.time, 60),'m') as HOURS
FROM table t;
Using DATE_ADD is what you want
SELECT DATE_ADD(starttime, INTERVAL 300 MINUTE) as endtime;
EDIT:
Okay, I think i understand you know. The code below could probably be condensed, however, I left it verbose for readability.
SELECT CASE WHEN
DATE_ADD(TIMESTAMP(starttime), INTERVAL 300 MINUTE)
BETWEEN TIMESTAMP(DATE(starttime),'09:00')
AND TIMESTAMP(DATE(starttime),'17:30')
THEN
## starttime plus 5 hours, is still in range of current business window
DATE_ADD(starttime, INTERVAL 300 MINUTE)
WHEN TIMESTAMP(starttime) > TIMESTAMP(DATE(starttime),'17:30') THEN
## startime falls after business hours, add it to the following day at 09:00
DATE_ADD(TIMESTAMP(DATE(starttime),'09:00'),
INTERVAL (1440 /*24 hours (i.e. next day)*/ + 300 ) MINUTE
)
ELSE
## if the starttime falls within business hours, but extends into the next business day,
## calculate the difference up to 17:30, add to the following day, after 09:00
DATE_ADD(TIMESTAMP(DATE(starttime),'09:00'),
INTERVAL (
1440 + /*24 hours (i.e. next day)*/
300 - /* standard working day */
ABS(
TIMESTAMPDIFF(MINUTE, TIMESTAMP(DATE(starttime),'17:30'), starttime)
) /* less yesterday's minutes */
) MINUTE
)
END AS endtime
;

Calculating "TotalshiftTiming - (Break01 + Lunch +Break02)

I have a table that displays shift start time, break 01 start time, break 01 end time, lunch start time, lunch end time, break 02 start time, break 02 end time,
shift end time.
Here I wanted to calculate everything in minutes.
Time = TotalShiftTime - ((break01Start - break01endtime) + (lunchstart - lunchend) + (break02start - break02end))
I want to calculate this in minutes on daily basis. I want to calculate this with respect to start date and end date which i wanted to give as input.
It has to be like
[(endDate - startDate) * Time]
If my endDate is 07/03/2018 and startDate is 04/03/2018 I want it to be [3 * Time].
PS: I don't have a column for startDate and endDate. I want to get cumulative minutes when I select system date.
How can I achieve this?
Shiftstart | Brk01start | Brk01end | LunchStart | LunchEnd | Brk02Start | Brk02end | Shiftend
8:00:00 | 11:15:00 | 11:45:00 | 13:00:00 | 13:30:00 | 15:15:00 | 15:30:00 | 17:00:00

Select distinct and get sum of timestamp differences

I don't know if this is possible, but it'd be really awesome. I have a table of sign-ins for people who are logging time on different projects and I need to compile a report of time logged for each project for a given time period.
My table looks something like this:
id | project | time_in | time_out | break
----------------------------------------------------------------
1 | 1 | 2014-12-07 05:00:00 | 2014-12-07 10:00:00 | 30
2 | 2 | 2014-12-07 06:00:00 | 2014-12-07 13:00:00 | 15
3 | 1 | 2014-12-07 14:00:00 | 2014-12-07 18:00:00 | 0
4 | 3 | 2014-12-07 08:30:00 | 2014-12-07 18:45:00 | 75
5 | 2 | 2014-12-07 12:00:00 | 2014-12-07 16:30:00 | 0
What I'd like to be able to do is get a report of the time logged for each project given a date range, i.e. the total time, probably in seconds, logged for each project.
time_in and time_out are fields of type TIMESTAMP; break is an integer representing the number of minutes the person was on break. I need to get the sum of time_out - time_in - break for each project, e.g. for December 7:
project | time
---------------
1 | 34200
2 | 40500
3 | 34200
This is all I have so far:
SELECT DISTINCT
`project`
FROM `sign_ins`
WHERE
`time_in` >= '2014-12-07 00:00:00' AND
`time_out` <= '2014-12-08 00:00:00';
I appreciate your help on this, SO community. You guys are so brilliant.
You can get the difference in seconds by converting the date/time values to Unix time stamps. Then, just aggregate the differences using sum():
SELECT project,
SUM(UNIX_TIMESTAMP(time_out) - UNIX_TIMESTAMP(time_in) - (break * 60)) as DiffSecs
FROM `sign_ins`
WHERE `time_in` >= '2014-12-07 00:00:00' AND
`time_out` <= '2014-12-08 00:00:00'
GROUP BY project;

Find n occurrences within a date range that is within a larger date range

In MySQL, I have a table that records user "actions" (an action can be any number of things: a click, a purchase, etc). The table looks like so, where action_id is unique:
+--------------------------------------------+
| table_actions |
+--------------------------------------------+
| action_id | user_id | date_created |
+-----------+---------+----------------------+
| 1 | 321 | 2011-01-21 06:00:00 |
+-----------+---------+----------------------+
| 2 | 123 | 2011-02-21 06:00:00 |
+-----------+---------+----------------------+
| 3 | 456 | 2011-03-21 06:00:00 |
+-----------+---------+----------------------+
| 4 | 654 | 2011-04-21 06:00:00 |
+--------------------------------------------+
I want to find the number of distinct user_ids that took three actions no more than one year apart within a 30 month date range. My first try was this:
select ta.user_id
from table_actions ta
where ta.date_created > DATE_SUB(now(),interval 30 month)
group by ta.user_id
having COUNT(ta.action_id) > 2 AND DATEDIFF(MAX(ca.created_at),MIN(ca.created_at)) > 364;
This runs just fine, but errors in only checking the difference between a users first and last action. If user's first and last action are 30 months apart, but somewhere in that span of time they took 3 actions in 3 days, they would not be counted by my query.
My research found a few posts on date ranges, but none that looked for a certain number of occurrences within a range within a range.
I'm assuming this could involve a loop or row numbering of some kind, but I've quickly reached the limits of my knowledge.
Update 1:
If a real world example would help:
Jane takes action in March 2010, March 2011, April 2011 and December 2011.
John takes action in January 2010, January 2011, February 2011 and March 2012.
Each have take 3 or more actions in the past 30 months, but only Jane has taken 3 or more actions that fell within a 12 month period inside the last 30 months. I'm looking for a query that returns all the Janes.
Where I'm getting stuck is accounting for the fact that a user can take any number of actions in the past 30 months. If they were limited to only 3 actions, this would be simple. But, I don't know how to take a user who has taken 5 actions in the past 30 months and check if 3 of those actions fell in a year long period.
Hopefully that helps clarify. Thanks everyone.