How to add hours matching a mysql query? - mysql

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'])).

Related

Calculate monthly average

I have a table which is recording utilization of a product.
In logistics, there's a parameter called commodity average monthly utilization (CAMU) this keep track of your monthly utilization to date.
here's my table tblTransaction
desired output would be this
qry_camu
Explanation:
prod1 has a total of 102 issuance recorded in 2 months (Feb and Sep) - 102/2 = 51
prod2 has a total of 26 issuance recorded in 2 months (Apr and May) - 26/2 = 13
Thank you in advance!
Assuming the table is created with the standard date format for the column date.
So the query will be as below
select
commodity,
sum(issuance)/count(distinct extract(year_month from date)) as CAMU,
round(sum(issuance)/count(distinct extract(year_month from date)),2) as 'CAMU(rounded)'
from
tbltransaction
group by
commodity;
Output:
commodity | CAMU | CAMU(rounded)
:-------- | ------: | ------------:
prod1 | 51.0000 | 51.00
prod2 | 13.0000 | 13.00
db<>fiddle here

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
;

SQL: aggregation from different tables with different date formats

Working with the following sql tables:
table: fiscal
DateID | date | fiscal_year | fiscal_week
20170101 2017-01-01 00:00:00.0 2017 2017 WK 01
20170102 2017-01-02 00:00:00.0 2017 2017 WK 01
table: email_info
email_id | email_name | email_subjectline
123 New_Year_2017 Welcome the new year!
345 Reminder Don't forget
table: sent_info
email_id | sent_date
123 | 1/1/2017 8:58:39 PM
345 | 1/2/2017 6:33:39 AM
table: click_info
recipient | email_id | click_date
XYZ 123 1/7/2017 4:25:27 PM
ABC 123 1/5/2017 3:13:56 AM
CDF 345 1/6/2017 2:20:16 AM
ABC 345 1/14/2017 3:33:25 AM
Obviously there are many rows in each table.
The joining between the email tables is straightforward.
SELECT *
FROM email_info
JOIN sent_info
ON sent_info.email_id = email_info.email_id
JOIN click_info
ON click_info.email_id = email_info.email_id
I am struggling with the following:
how to get all dates into the same format? ( I don't need the times,
only the day)
how to join the fiscal table so I can filter by fiscal week for example
how to count all clicks for an email for 7 days after the sent date (this cannot be hard-coded by dates, but must be dynamic)
This is the output I am looking for (filtered by fiscal week = 2017 WK 01):
email_id | email_name | sent_date | fiscal_week | Clicks
123 New_year_2017 1/1/2017 2017 WK 01 2
345 Reminder 1/2/2017 2017 WK 01 1
*Please note that the last click in the click_info table example was not counted, because it was beyond the 7 days after sent date.
** DateID is an integer and sent_date and click_date are strings/varchar
assuming that dateId is varchar and the others are datetime should be
select a.email_id, a.email_name, date(b.sent_date), c.fiscal_week, count(d.click_date)
from email_info a
inner join fiscal c on str_to_date(c.dateID, '%Y%m%d') = date(b.sent_date)
inner join sent_info b on b.email_id = c.email_id
inner join click_info d on d.email_id = b.email_id
and date(d.click_date) between date(b.sent_date) and DATEADD(week,1,date(b.sent_date))
group by a.email_id, a.email_name, date(b.sent_date), c.fiscal_week
PS do the fact the query struct is defined if you have other format you can convert properly and change the single piece

Group dates by only month and year

Assuming I have a table like the following:
id | assignment | duedate
1 | Math | 2012-01-01
2 | History | 2012-02-02
3 | Science | 2012-01-01
4 | Government | 2012-02-01
5 | Government | 2013-01-13
6 | History | 2013-03-13
Is it possible to make some sql query such that I get a grouping of all the dates by month and year? Is there some possibility that I could get a sorted result of:
duedatemonth | count
January 2012 | 2
Feburary 2012 | 2
January 2013 | 1
March 2013 | 1
I know you can GROUP BY duedate, but that only groups those with the same month, day, and year instead of just month and year.
Would it be then possible to even further group it such that it factors in "assignment" to obtain a resulting table of
id | duedatemonth | count
1 | January 2012 | 2
3 | January 2012 | 2
2 | Feburary 2012 | 2
4 | Feburary 2012 | 2
5 | January 2013 | 1
6 | March 2013 | 1
try this
SELECT DATE_FORMAT(duedate,'%M %Y') duedatemonth, COUNT(*) count
FROM Table1
GROUP BY year(duedate), MONTH(duedate)
DEMO HERE
will output this:
DUEDATEMONTH COUNT
January 2012 2
February 2012 2
January 2013 1
March 2013 1
Use the string functions YEAR and MONTH.
SELECT YEAR(duedate), MONTH(duedate), COUNT(*)
FROM sparkles
GROUP BY YEAR(duedate), MONTH(duedate)
Use MONTHNAME or DATE_FORMAT to get the name of the month.
You can use this query.
SELECT DATE_FORMAT(duedate, '%M %Y') duedatemonth, COUNT(1) `count`
FROM Tbl
GROUP BY DATE_FORMAT(duedate, '%M %Y')

mysql counting in a particular time period

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.