Search record between 3 date ranges - php

I need to output data from a DB table that selects records between 3 (not 2) date/time ranges
E.g. start time : 2019-09-07 18.00
end time : 2019-09-07 20.00
so the user should be able to see the record 25 minutes before the start date-time (6.p.m - 18.00), during the event but not after the end date-time (8.p.m -20.00).
I've tried
db->query = "SELECT o_id, schedule, date, start_time, end_time FROM working_schedule WHERE o_id = '".$user_id."'
AND (start_time <= '".date('Y-m-d\TH:i:s', strtotime("-25 minutes"))."' AND start_time >= '".date('Y-m-d\TH:i:s')."')
AND end_time >= '".date('Y-m-d\TH:i:s')."'";
but the result is NULL.
For reference HERE'S a sql fiddle.
Thanks in advance for pointing me in the right direction.

Do you need this ?
select * from working_schedule
where
NOW() BETWEEN DATE_SUB(start_time,INTERVAL 25 MINUTE) AND end_time

Related

Need help on framing up the mysql query?

I have a table records with start time,end time, duration.
Assume I have three records A,B,C where:
A record has start time at 2019-09-10 00:12:00 and its end time at 2019-09-10 02:30:44.
B record has start time at 2019-09-10 17:34:00 and end time at 2019-09-10 19:34:00
C record had start time at 2019-09-10 22:34:00 and end time at 2019-09-11 02:30:30
Now I have to frame a query where a,b,c records to be pulled within the start time has 2019-09-10 00:00:00 and end time as 2019-09-10 23:59:59 and C record should also be counted till 23:59:59 with a duration.
I have tried but the C record is not displaying it because the end time is different.
Query:
Select
start_time,
end_time,
duration as timespent
from
tablename
where
userid IN(91) AND
'start_time' >='2019-09-10 00:00:00' AND
'end_time' <='2019-09-10 23:59:59'
Can anyone help me how can i frame it.
I am using php codeigniter has a frame work.
Look for sessions witch started or ended on that day :
SELECT start_time, end_time, duration AS timespent
FROM tablename
WHERE DATE(start_time) = '2019-09-10' OR DATE(end_time) = '2019-09-10'
SELECT id, start_time, CASE WHEN end_time > #end_time
THEN #end_time
ELSE end_time
END as end_time
FROM YourTable
WHERE start_time <= #end_time
AND end_time >= #start_time
If you dont know use variables try this first:
SELECT id, start_time, CASE WHEN end_time > '2019-09-10 23:59:59'
THEN '2019-09-10 23:59:59'
ELSE end_time
END as end_time
FROM YourTable
WHERE start_time <= '2019-09-10 23:59:59'
AND end_time >= '2019-09-10 00:00:00'
The duration is the difference between end_time and start_time. But start_time must be 00:00:00 if it's yesterday and end_time 23:59:59 if it's tomorrow. Right ?
Use LEAST() AND GREATEST() to do something like this :
SELECT start_time, end_time, LEAST('2019-09-10 23:59:59', end_time) - GREATEST('2019-09-10 00:00:00', start_time) AS timespent
FROM tablename
WHERE DATE(start_time) = '2019-09-10' OR DATE(end_time) = '2019-09-10'
timespent will be a numeric, not an int.

Check time between two columns in MySQL

I have a MySQL table, booking:
id shop_id date start_time end_time
1 21 2019-1-13 09:00 10:00
2 21 2019-1-13 11:00 11:30
Now before I a insert record into booking table I want to check whether date and time is already booked or not.
How can I do this?
I tried with the following code:
SELECT * FROM booking
WHERE CAST(start_time as date) BETWEEN
'2012-08-30' AND '2012-08-31';
If I understand correctly, you'll have separate values for #date, #start_time, and #end_time that you want to check in the table.
To return all overlaps:
SELECT b.*
FROM booking b
WHERE #date = b.date AND
#end_time >= b.start_time AND
#start_time < b.end_time;
As per your table structure it is better to use
SELECT * FROM booking
WHERE CAST(CONCAT(date,' ',start_time)AS timestamp)
BETWEEN '2012-08-30' AND '2012-08-31';
Otherwise it is better to use full timestamp for both start_time and end_time.

mysql group_concat showing all dates

I have 2 tables:
profile userid, fname,lname
schedule: userid, date, start_time, end_time
Here is my query .
select *, group_CONCAT(distinct(date),'_',start_time,'_',end_time)
as dateformat FROM profile, schedule WHERE profile.userid =
schedule.pid
This returns all dates from the table. But what I am trying to do is return only certain days like:
date >= DATE(NOW()) and date <= date(now() + 2 day)
So today tomorrow and the day after.
No matter what I try it just returns all dates in the schedule database. I need this to return 2 rows userid 5 has 1 row in profile but 5 rows in schedule and userid 6 has 1 row in profile and 2 rows in schedule the query works fine its just returning all dates and not the dates within the
"date >= DATE(NOW()) and date <= date(now() + 2 day)"
did you try GROUP BY?
like WHERE profile.userid = schedule.pid GROUP BY date
select profile.userid,schedule.userid, group_CONCAT(distinct(date),'_',start_time,'_',end_time) as dateformat FROM profile, schedule WHERE profile.userid = schedule.userid and date >= DATE(NOW()) and date <= date(now() + interval 2 day);
That did it for now!! Now I can use the dateformat variable in php to parse out my results.
kanishka panamaldeniya - thanks for your suggestion!

MySQL BETWEEN DATE RANGE

I have a scenario where I need to pull up delivery dates based on a table below (Example)
job_id | delivery_date
1 | 2013-01-12
2 | 2013-01-25
3 | 2013-02-15
What I'm trying to do is show the user all the delivery dates that start with the earliest (in this case it would be 2013-01-12) and add an another 21 days to that. Basically, the output I would expect it to show of course, the earliest date being the starting date 2013-01-12 and 2013-01-25. The dates past the February date are of no importance since they're not in my 21 date range. If it were a 5 day range, for example, then of course 2013-01-25 would not be included and only the earliest date would appear.
Here is main SQL clause I have which only shows jobs starting this year forward:
SELECT date, delivery_date
FROM `job_sheet`
WHERE print_status IS NULL
AND job_sheet.date>'2013-01-01'
Is it possible to accomplish this with 1 SQL query, or must I go with a mix of PHP as well?
You can use the following:
select *
from job_sheet
where print_status IS NULL
and delivery_date >= (select min(delivery_date)
from job_sheet)
and delivery_date <= (select date_add(min(delivery_date), interval 21 day)
from job_sheet)
See SQL Fiddle with Demo
If you are worried about the dates not being correct, if you use a query then it might be best to pass in the start date to your query, then add 21 days to get the end date. Similar to this:
set #a='2013-01-01';
select *
from job_sheet
where delivery_date >= #a
and delivery_date <= date_add(#a, interval 21 day)
See SQL Fiddle with Demo
SELECT date,
delivery_date
FROM job_sheet
WHERE print_status IS NULL
AND job_sheet.date BETWEEN (SELECT MIN(date) FROM job_sheet) AND
(SELECT MIN(date) FROM job_sheet) + INTERVAL 21 DAY
SELECT j.job_id
, j.delivery_date
FROM `job_sheet` j
JOIN ( SELECT MIN(d.delivery_date) AS earliest_date
FROM `job_sheet` d
WHERE d.delivery_date >= '2013-01-01'
) e
ON j.delivery_date >= e.earliest_date
AND j.delivery_date < DATE_ADD(e.earliest_date, INTERVAL 22 DAY)
AND j.print_status IS NULL
ORDER BY j.delivery_date
(The original query has a predicate on job_sheet.date; the query above references the d.delivery_date... change that if it is supposed to be referencing the date column instaed.)
If the intent is to only show delivery_date values from today forward, then change the literal '2013-01-01' to an expression that returns the current date, e.g. DATE(NOW())

How to minimize the load in queries that need grouping with different invervals?

I'm looking for a best practice advice how to speed up queries and at the same time to minimize the overhead needed to invoke date/mktime functions. To trivialize the problem I'm dealing with the following table layout:
CREATE TABLE my_table(
id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
important_data INTEGER,
date INTEGER);
The user can choose to show 1) all entries between two dates:
SELECT * FROM my_table
WHERE date >= ? AND date <= ?
ORDER BY date DESC;
Output:
10-21-2009 12:12:12, 10002
10-21-2009 14:12:12, 15002
10-22-2009 14:05:01, 20030
10-23-2009 15:23:35, 300
....
I don't think there is much to improve in this case.
2) Summarize/group the output by day, week, month, year:
SELECT COUNT(*) AS count, SUM(important_data) AS important_data
FROM my_table
WHERE date >= ? AND date <= ?
ORDER BY date DESC;
Example output by month:
10-2009, 100002
11-2009, 200030
12-2009, 3000
01-2010, 0 /* <- very important to show empty dates, with no entries in the table! */
....
To accomplish option 2) I'm currently running a very costly for-loop with mktime/date like the following:
for(...){ /* example for group by day */
$span_from = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i, date("Y", $time_min));
$span_to = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i+1, date("Y", $time_min));
$query = "..";
$output = date("m-d-y", ..);
}
What are my ideas so far? Add additional/ redundant columns (INTEGER) for day (20091212), month (200912), week (200942) and year (2009). This way I can get rid of all the unnecessary queries in the for loop. However I'm still facing the problem to very fastly calculate all dates that doesn't have any equivalent in database. One way to simply move the problem could be to let MySQL do the job and simply use one big query (calculate all the dates/use MySQL date functions) with a left join (the data). Would it be wise to let MySQL take the extra load? Anyway I'm reluctant to use all these mktime/date in the for loop. Since I have complete control over the table layout and code even suggestions with major changes are welcome!
Update
Thanks to Greg I came up with the following SQL query. However it still bugs me to use 50 lines of sql statements - build up with php - that maybe could be done faster and more elegantly otherwise:
SELECT * FROM (
SELECT DATE_ADD('2009-01-30', INTERVAL 0 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 1 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 2 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 3 DAY) AS day UNION ALL
......
SELECT DATE_ADD('2009-01-30', INTERVAL 50 DAY) AS day ) AS dates
LEFT JOIN (
SELECT DATE_FORMAT(date, '%Y-%m-%d') AS date, SUM(data) AS data
FROM test
GROUP BY date
) AS results
ON DATE_FORMAT(dates.day, '%Y-%m-%d') = results.date;
You definitely shouldn't be doing a query inside a loop.
You can group like this:
SELECT COUNT(*) AS count, SUM(important_data) AS important_data, DATE_FORMAT('%Y-%m', date) AS month
FROM my_table
WHERE date BETWEEN ? AND ? -- This should be the min and max of the whole range
GROUP BY DATE_FORMAT('%Y-%m', date)
ORDER BY date DESC;
Then pull these into an array keyed by date and loop over your data range as you are doing (that loop should be pretty light on CPU).
Another idea is not to use string inside the query. Transform the string parameter to datetime, on mysql.
STR_TO_DATE(str,format)
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html

Categories