I have a MySQL table looking like this. It's basically a time sheet for tasks.
id | task | user | start | stop | running
------+--------+--------+-----------------------+-----------------------+-----------
1 | 12 | 2 | 2009-10-01 10:05:00 | 2009-10-01 14:23:00 | 0
1 | 13 | 4 | 2009-10-05 08:58:00 | 2009-10-05 12:16:00 | 0
1 | 14 | 3 | 2009-10-05 20:30:00 | 2009-10-05 22:00:00 | 0
I want to sum the time spent:
1) Today
2) Yesterday
3) This week
4) Last week
5) This month
6) Last month
I don't need the queries for each of theese, but just the first one to get me started. I'm not that familiar with different date functions in MySQL, and I think it's difficult to read and navigate through their documentation..
It's not THAT difficult to navigate through MySQL documentation.
You need TIMEDIFF() and TIME_TO_SEC functions.
select SUM(TIME_TO_SEC(TIMEDIFF(stop, start))) from my_table
where start >= CURRENT_DATE() and stop <= CURRENT_DATE() + INTERVAL 1 DAY
will get you total time (in seconds) spent on tasks today. Look at DATE_SUB() if you're going to specify criteria for other ranges (e.g. last month, etc) in MySQL instead of supplying them as parameters to your query.
SELECT 'TODAY' Date, SUM(TIME_TO_SEC(TIME_DIFF(stop - start))) TimeSpent
FROM table1
WHERE start >= CURDATE()
AND stop < CURDATE() + INTERVAL 1 DAY
Related
I am working on a booking system where users can book certain services online. I am stuck on finding and displaying available time slots within a specific day. I know the length of the needed time slot is 1 hour and the business hours.
Is there a way to show time slots that has not yet been booked on a certain day and display only the available time slots that is available to be booked in a dropdown select form?
If a customer selects a specific day and clicks "Select Day" then it needs to query the DB and return the results.
My SQL structure is as follows
|id | title | start_time | end_time | booking_date |
| 1 | Name1 | 2022-05-12 08:00:00 | 2022-05-12 09:00:00 | 2022-05-12 |
| 2 | Name2 | 2022-05-12 10:00:00 | 2022-05-12 11:00:00 | 2022-05-12 |
| 3 | Name3 | 2022-05-12 13:00:00 | 2022-05-12 14:00:00 | 2022-05-12 |
| 4 | Name4 | 2022-05-12 14:00:00 | 2022-05-12 15:00:00 | 2022-05-12 |
as per above the select form should display the timeslots that is not already taken.
09:00 - 10:00
12:00 - 13:00
15:00 - 16:00
It would be something like:
select
id, title
from
<table>
where
start_time between '2022-05-12 00:00:00' and '2022-05-12 11:59:59'
and
booking_date is null
I don't know the name of your table, so you would need to replace <table> with that. I'm also assuming that "booking_date" will have a value to indicate that time slot has been reserved, that it's a date field, and it will be null if that slot hasn't been selected. However, booking_date could have a different purpose.
This is a lazy answer
(because I think just use SQL will do it, use subSelect and other function, but I don't know how to do, sorry.)
get today occupy time:
SELECT id, TIME(start_time) AS s_time FROM tablename
WHERE start_time >= '2022-05-12 00:00:00'
AND start_time < '2022-05-13 00:00:00'
diff time in php:
$sqlResult = []; // sql result
$timeAll = [
'00:00:00',
'01:00:00',
'02:00:00',
'03:00:00',
... // TODO: we need fill it
'23:00:00',
];
foreach ($sqlResult as $item) {
if (isset($timeAll[$item['s_time']])) {
unset($timeAll[$item['s_time']]);
}
}
return $timeAll;
// TODO: javascript or other client code can use it.
ref knowledge link:
MySQL SELECT WHERE datetime matches day (and not necessarily time)
If you choose 2022-05-26, and Peter is occupying room F25 from 2022-05-16 until 2022-05-29, it means the date you select must be out of this range.
So, the query below will only return rooms that were not booked on that day.
SELECT b.id, b.room_id as available_room FROM booking as b
WHERE(
unix_timestamp('$mydate')
NOT BETWEEN unix_timestamp(b.start_date)
AND unix_timestamp(b.end_time)
)
AND unix_timestamp(b.end_time) < unix_timestamp('$mydate');
Assuming $mydate is the variable that contains the date selected by the user, the above query will return rooms that will be available in the future on that particular day.
I'm trying to add a column to a production hours dataset that will tell if a provider who worked last week was also working three weeks earlier. The current dataset looks something like this:
RowID | ProviderID | ClientID | DOS | DOS (Week) | Hours
1 | 1111111111 | 22222222 | 11/2/2020 | 11/1/2020 | 2.5
2 | 1111111111 | 33333333 | 11/5/2020 | 11/1/2020 | 1
3 | 1111111111 | 44444444 | 10/13/2020 | 10/11/2020 | 3
I'm trying to get an extra column 'Active 3 Weeks Prior' with y/n or 1/0 for values. For the above table, let's assume the provider started on 10/13/20. The new column would ideally populate like this:
RowID | ProviderID | ClientID | DOS | DOS (Week) | Hours | Active 3 weeks Prior
1 | 1111111111 | 22222222 | 11/2/2020 | 11/1/2020 | 2.5 | Yes
2 | 1111111111 | 33333333 | 11/5/2020 | 11/1/2020 | 1 | Yes
3 | 1111111111 | 44444444 | 10/13/2020 | 10/11/2020 | 3 | No
A couple extra tidbits: our org uses Sunday as the start of the week so DOS (Week) is the Sunday prior to the date of service. From what I've been reading so far, it seems like the solution here is some kind of self join, where the base production records are aggregated into weekly hours and compared with that same providerID's records for DOS (Week) - 21.
The trouble I'm having is: whether I'm on the right track in the first place with the self-join and how I would generate the y/n values based on the success or failure to find a matching value. Also, I suspect that joining based on a concatenate of ProviderID and DOS(Week) might be flawed? This is what I've been playing with so far.
Please let me know if I can clarify the question at all or am missing something very obvious. I truly appreciate any help, as I've been trying to figure out the right search terms to get a clue on the answer for a few days now.
If you are running MySQL 8.0, you can use window functions and a range specification:
select t.*,
(
max(providerid) over(
partition by providerid
order by dos
range between interval 3 week preceding and interval 3 week preceding
) is not null
) as active_3_weeks_before
from mytable t
It is not really clear from your explanation and data what you mean by was also working three weeks earlier. What the query does is, for each row, to check if another row exists with the same supplier and a dos that is exactly 3 week before the dos of the current row. This can easily be adapted for some other requirement.
Edit: if you want to check for any record within the last 3 weeks, you would change the window range to:
range between interval 3 week preceding and interval 1 day preceding
And if you want this in MySQL < 8.0, where window functions are not available, then you would use a correlated subquery:
select t.*,
exists (
select 1
from mytable t1
where
t1.providerid = t.provider_id
and t1.dos >= t.dos - interval 3 week
and t1.dos < t.dos
) as active_3_weeks_before
from mytable t
Assuming that I have a table like this:
+----+----------------+------------+------------+-----------+----------+
| id | time_needed | date_start | date_stop | hour_start| hour_stop |
+----+----------------+------------+------------+-----------+----------+
| 1 | 30 | 2018-08-06 | 2018-08-06 | 08:00:00 | 08:30:00 |
| 2 | 96 | 2018-08-06 | 2018-08-06 | 10:45:00 | 14:21:00 |
| 3 | 20 | NULL | NULL | NULL | NULL |
| 4 | 56 | NULL | NULL | NULL | NULL |
+----+----------------+------------+------------+-----------+----------+
I know when I'll execute the operations 1 and 2, But instead for the 3 and 4 I just know the the time spent to execute the operations (20 and 56 minutes)
How can I check with mysql when I can execute the operation 3? I mean, is there a possibility to check when I have free time and for how long?
Looking at the table I can say that I have free time from the 08:31 to 10:44, but there is a way to check it with mysql?
EDIT
I would like to see the time free, beetween 8 am and 18 pm.
What you are demanding is not (all alone) a task of mysql. mysql can give you the DATA according to your query - but your programming language should add the logic of scheduling entries, whenever possible.
At first i would start with the following database changes:
Combine the date / hour columns into a datetime column.
remove the end_date / end_hour - you always can calcluate this with date_start + time_needed
So, you end up with a datatable like this:
+----+----------------+---------------------+
| id | time_needed | date_start |
+----+----------------+---------------------+
| 1 | 30 | 2018-08-06 08:00:00 |
| 2 | 96 | 2018-08-06 14:21:00 |
+----+----------------+---------------------+
Now, all you need to do is: Join the table with itself, and make sure everything is calculated as it should be:
-- new Task takes 25 Minutes.
SELECT DISTINCT L.* FROM time_table L LEFT JOIN time_table R
-- compare with every later schedule
on L.date_start < R.date_start
WHERE
-- use only rows that have enough time for the task that should be scheduled
(date_add(L.date_start, INTERVAL L.time_needed + 25 MINUTE ) < R.date_start
-- and only in the future
and date_add(L.date_start, INTERVAL L.time_needed MINUTE) > NOW()
-- due to the join, it might happen that we ignore entries in between.
-- make sure, there is no other task in the calculated timespan!
and not exists
(SELECT id FROM time_table x WHERE
x.date_start > L.date_start AND
x.date_Start < date_add(L.date_start, INTERVAL L.time_needed + 25 MINUTE) )
)
-- and ofc. the last row in the schedule.
OR isnull (R.date_start);
This returns both datarows, as 25 minutes can be scheduled right after every other task.
http://sqlfiddle.com/#!9/02020d8/1
14:21 - 08:00 is 6:21, and 30 minutes are "booked". So the gap is 5:51 - so a 350 Minute Task should fit after 08:00 - a 351 Minute Task not:
350 minutes to be scheduled:
http://sqlfiddle.com/#!9/02020d8/2
351 minutes to be scheduled:
http://sqlfiddle.com/#!9/02020d8/3
All you got to do afterwards:
Take the smalles id, and insert your schedule right after it. Remember, date_start will be prior_date_start + prior_time_needed.
See this example as well: Scheduling a 20 minute Task would have 3 options with the example data (Added 2 columns for your convenience):
http://sqlfiddle.com/#!9/02020d8/8
I have seen so many questions similar to this, but they all seem to be tailored to highlighting when date ranges are overlapping, I need the opposite.
Lets say I have a table like so
id| start_date | end_date | room_id
1 | 15/05/2018 | 30/06/2020 | 1
2 | 01/11/2018 | 31/10/2019 | 2
3 | 01/08/2020 | 31/07/2022 | 1
4 | 01/12/2019 | 30/11/2021 | 2
5 | 01/08/2020 | 31/07/2022 | 3
As you can see there are multiple bookings for each room. I need to be able to specify either a single start/end date or both, and get back what DOESN'T overlap (i.e, the available rooms)
For example, if i specified just a start date of 01/05/2018 then every room will return, or if i specify just an end date of 30/07/2020 then every room will return because neither of those dates are between the start and end date of each booking. Even though id 1 has a booking that ends on 30/06/2020 and a new one that starts on 01/08/2020, it would still be available because someone could book between those 2 dates.
If I specified both start and end dates, it searches through and returns only the rooms that have no bookings between the 2 dates at all.
I have read plenty of questions online and the logic seems to be
SELECT *
FROM bookings
WHERE $start_date < expiry_date AND $end_date > start_date
which i understand, but if I ran this query above with the following dates
SELECT *
FROM bookings
WHERE '2018-10-01' < expiry_date AND '2019-10-01' > start_date
it returns
id| start_date | end_date | room_id
1 | 15/05/2018 | 30/06/2020 | 1
2 | 01/11/2018 | 31/10/2019 | 2
How do I get it so that when I pass either a start date, end date or BOTH it returns the rooms that are available?
By De Morgan's Laws, we can negate the overlapping range query you gave as follows:
SELECT *
FROM bookings
WHERE $start_date >= expiry_date OR $end_date <= start_date;
The expression ~(P ^ Q) is equivalent to ~P V ~Q.
I need to create a date range in a table that houses transaction information. The table updates sporadically throughout the week from a manual process. Each time the table is updated transactions are added up to the previous Sunday. For instance, the upload took place yesterday and so transactions were loaded through last Sunday (Feb 26th). If it had been loaded on Wednesday it would still be dated for Sunday. The point is that I have a moving target with my transactions and also when the data is loaded to the table. I am trying to fix my look back period to the date of the latest transaction then go three weeks back. Here is the query that I came up with:
SELECT distinct TransactionDate
FROM TransactionTABLE TB
inner join (
SELECT distinct top 21 TransactionDate FROM TrasactionTABLE ORDER BY TransactionDate desc
) A on TB.TransactionDate = A.TransactionDate
ORDER BY TB.TransactionDate desc
Technically this code works. The problem that I am running into now is when there were no transactions on a given date, such as bank holidays (in this case Martin Luther King Day), then the query looks back one day too far.
I have tried a few different options including MAX(TransactionDate) but if I use that in a sub-query or CTE then use the new value in a WHERE statement as a reference I only get the max value or the value I subtract that statement by. For instance if I say WHERE TransactionDate >= MAX(TransactionDate)-21 and the max date is Feb 26th then the result is Feb 2nd instead of the range of dates from Feb 2nd through Feb 26th.
IN SUMMARY, what I need is a date range looking three weeks back from the date of the latest transaction date. This is for a daily report so I cannot hardcode the date in. Since I am also using Excel Connections the use of Declare statements is prohibited.
Thank you StackOverflow gurus in advance!
You could use something like this:
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (21)
[Date]=convert(date,dateadd(day, row_number() over (order by (select 1))-1
, dateadd(day,-20,(select max(TransactionDate) from t) ) ) )
from n as deka
cross join n as hecto
order by [Date]
)
select Date=convert(varchar(10),dates.date,120) from dates
rextester demo: http://rextester.com/ZFYV25543
returns:
+------------+
| Date |
+------------+
| 2017-02-06 |
| 2017-02-07 |
| 2017-02-08 |
| 2017-02-09 |
| 2017-02-10 |
| 2017-02-11 |
| 2017-02-12 |
| 2017-02-13 |
| 2017-02-14 |
| 2017-02-15 |
| 2017-02-16 |
| 2017-02-17 |
| 2017-02-18 |
| 2017-02-19 |
| 2017-02-20 |
| 2017-02-21 |
| 2017-02-22 |
| 2017-02-23 |
| 2017-02-24 |
| 2017-02-25 |
| 2017-02-26 |
+------------+
I just found this for looking up dates that fall within a given week. The code can be manipulated to change the week start date.
select convert(datetime,dateadd(dd,-datepart(dw,convert(datetime,convert(varchar(10),DateAdd(dd,-1/*this # changes the week start day*/,getdate()),101)))+1/*this # is used to change the week start date*/,
convert(datetime,convert(varchar(10),getdate(),21))))/*also can enter # here to change the week start date*/
I've included a screenshot of the results if you were to include this with a full query. This way you can see how it looks with a range of dates. I did a little manipulation so that the week starts on Monday and references Monday's date.
Since I am only looking back three weeks a simple GETDATE()-21 is sufficient because as the query moves forward through the week it will look back 21 days and pick the Monday at the beginning of the week as my start date.