I have a table that contains events data. I also have a list of dates that I need to check through. So I loop though the given dates and query my table. I need to select the events that we on a given date and if the date is the same as today, I only need events that took place before certain time. The time is stored in a military format, like 14:30.
I think I've overcomplicated my query logic:
$current_date = date('Y-m-d');
$current_time = date('H:i');
The reason I use PHP time and date, because I can have an accurate time from a server I control. MySQL time is off by a few hours...
SELECT *
FROM events
WHERE org.id = ".$ID."
AND (
(
DATE(events.date) = '".$givenDate."'
AND
'".$givenDate."' < '".$current_date."'
)
OR
(
DATE(events.date) = '".$givenDate."'
AND
'".$givenDate."' < '".$current_date."'
AND
events.time < '".$current_time."'
)
)
SELECT *
FROM events
WHERE org.id = ".$ID."
AND date(events.date) = '".$givenDate."'
and if ('".$givenDate."' = '".$current_date."',
events.time < '".$current_time."', true)
Related
This is my request query :
SELECT
COUNT(shedule_line.id) AS total_available
FROM
shedule_line
WHERE
shedule_line.salle_id = :salle AND
shedule_line.date = :date AND
(
(shedule_line.start_at < :start_at AND shedule_line.end_at > :end_at) OR
(shedule_line.start_at > :start_at AND shedule_line.end_at < :end_at) OR
(shedule_line.start_at < :end_at)
);
This is my shedule_line table:
I'll build the count of the courses that are going on in a room currently passing the room, the start time, the end time, the date.
I think the logic you want is:
SELECT COUNT(sl.id) AS total_in_use
FROM shedule_line sl
WHERE sl.salle_id = :salle AND
sl.date = :date AND
(sl.start_at < :end_at AND
sl.end_at > :start_at
);
Two time intervals overlap is one starts before the second ends, and the first ends after the first starts.
I think you are looking for something like this:
SELECT COUNT(`id`) AS `total_available`
FROM `shedule_line`
WHERE `salle_id` = 2
AND `date` = '2020-02-10'
AND `start_at` BETWEEN '10:00:00' AND '20:00:00'
AND `end_at` BETWEEN '10:00:00' AND '20:00:00';
OR
SELECT COUNT(`id`) AS `total_available`
FROM `shedule_line`
WHERE `salle_id` = 2
AND `date` = '2020-02-10'
AND `start_at` >= '10:00:00'
AND `end_at` BETWEEN '10:00:00' AND '20:00:00';
Check the result on SQL Fiddle
SELECT COUNT(shedule_line.id) AS total_available
FROM shedule_line
WHERE shedule_line.salle_id = :salle AND shedule_line.date = :date
AND (
shedule_line.start_at < CAST(:end_at as time)
AND shedule_line.end_at > CAST(:start_at as time)
)OR
(
shedule_line.start_at > CAST(:end_at as time)
AND shedule_line.end_at > CAST(:start_at as time)
);
Finally I found this solution which works well. Thank you all.
I need help optimizing the below querys for a recurrent calendar i've built.
if user fail to accomplish all task where date
This is the query i use inside a forech which fetched all dates that the current activity is active.
This is my current setup, which works, but is very slow.
Other string explained:
$today=date("Y-m-d");
$parts = explode($sepparator, $datespan);
$dayForDate2 = date("l", mktime(0, 0, 0, $parts[1], $parts[2], $parts[0]));
$week2 = strtotime($datespan);
$week2 = date("W", $week2);
if($week2&1) { $weektype2 = "3"; } # Odd week 1, 3, 5 ...
else { $weektype2 = "2"; } # Even week 2, 4, 6 ...
Query1:
$query1 = "SELECT date_from, date_to, bok_id, kommentar
FROM bokningar
WHERE bokningar.typ='2'
and date_from<'".$today."'";
function that makes the foreach move ahead one day at the time...
function date_range($first, $last, $step = '+1 day', $output_format = 'Y-m-d' )
{
$dates = array();
$current = strtotime($first);
$last = strtotime($last);
while( $current <= $last ) {
$dates[] = date($output_format, $current);
$current = strtotime($step, $current);
}
return $dates;
}
foreach:
foreach (date_range($row['date_from'], $row['date_to'], "+1 day", "Y-m-d")
as $datespan)
if ($datespan < $today)
Query 2:
$query2 = "
SELECT bok_id, kommentar
FROM bokningar b
WHERE b.typ='2'
AND b.bok_id='".$row['bok_id']."'
AND b.weektype = '1'
AND b.".$dayForDate2." = '1'
AND NOT EXISTS
(SELECT t.tilldelad, t.bok_id
FROM tilldelade t
WHERE t.tilldelad = '".$datespan."'
AND t.bok_id='".$row['bok_id']."')
OR b.typ='2'
AND b.bok_id='".$row['bok_id']."'
AND b.weektype = '".$weektype2."'
AND b.".$dayForDate2." = '1'
AND NOT EXISTS
(SELECT t.tilldelad, t.bok_id
FROM tilldelade t
WHERE t.tilldelad = '".$datespan."'
AND t.bok_id='".$row['bok_id']."')";
b.weektype is either 1,2 or 3 (every week, every even week, every uneven week)
bokningar needs INDEX(typ, date_from)
Instead of computing $today, you can do
and date_from < CURDATE()
Are you running $query2 for each date? How many days is that? You may be able to build a table of dates, then JOIN it to bokningar to do all the SELECTs in a single SELECT.
When doing x AND y OR x AND z, first add parenthes to make it clear which comes first AND or OR: (x AND y) OR (x AND z). Then use a simple rule in Boolean arithmetic to transform it into a more efficient expression: x AND (y OR z) (where the parens are necessary).
The usual pattern for EXISTS is EXISTS ( SELECT 1 FROM ... ); there is no need to list columns.
If I am reading it correctly, the only difference is in testing b.weektype. So the WHERE can be simply
WHERE b.weektype IN ('".$weektype2."', '1')
AND ...
There is no need for OR, since it is effectively in IN().
tilldelade needs INDEX(tilldelad, bok_id), in either order. This should make the EXISTS(...) run faster.
Finally, bokningar needs INDEX(typ, bok_id, weektype) in any order.
That is a lot to change and test. See if you can get those things done. If it still does not run fast enough, start a new Question with the new code. Please include SHOW CREATE TABLE for both tables.
I'm looking for a way to order my results based on the actual time. In my table yo can see values like:
1,23:45
2,9:45
3,27:43
When I do a query I would like to know how to order them based on their actual 24 hour time.
Ex:
3,3:43
2,9:45
1,23:45
Notice how it changes 27:43 to 3:43, and creates the order.
Where I am using it, in this query:
SELECT *,COALESCE(ADDTIME(s.`departure_time`,SEC_TO_TIME(rt.delay)),s.`departure_time`) as `rt_time` FROM `stop_times` s INNER JOIN `trips` t ON s.`trip_id` = t.`trip_id` INNER JOIN `stops` st ON st.`stop_id` = s.`stop_id` INNER JOIN `routes` r ON r.`route_id` = t.`route_id` LEFT JOIN `rt_trips` rt ON t.`trip_id` = rt.`trip_id` where (s.`stop_id` = 'CB900') and ( ( s.`departure_time` >= '00:50' and s.`departure_time` <= '05:50') OR ( s.`departure_time` >= '24:50' and s.`departure_time` <= '29:50') ) and (s.`pickup_type` = '0') and (t.`service_id` IN ('removed to make it easier')) HAVING (`rt_time` BETWEEN '01:50' and '05:50' ) ) OR ( `rt_time` BETWEEN '25:50' and '29:50' ) ORDER BY `order` ASC
Explanation:
Information is a transit schedule, that may go forward onto the next day which may be a saturday. So, times may become 25:50, where that means 1:50 the next day.
Thanks
Cyrus
Hmmm, if you just want to get a value between 0 and 24 hours, then I would do:
select concat(mod(substring_index(time_column, ':', 1) + 0, 24), ':',
substring_index(time_column, ':', -1)
)
Try this function on the time_column
concat(mod(substr(time_column,1,INSTR(time_column, ':')-1),24)
,substr(time_column,INSTR(time_column, ':'),3)
)
You might need to cast date to string to integer, do the maths, and again cast it to time. But the fiddle version seems to work properly on varchar to integer conversion. Check this
http://sqlfiddle.com/#!9/ff60f9/1
I'd like to count the number events that occur on each day over the last month, but also include a count of zero when no events are found. Is that possible?
Here's what I'm starting from...
SELECT COUNT(*) AS count,
DATE(usage_time_local) AS d
FROM usages
WHERE user_id=136
AND DATE(usage_time_local) >= DATE('2011-04-24')
AND DATE(usage_time_local) <= DATE('2011-05-24')
GROUP BY DATE(usage_time_local);
UPDATE: Given the answer, I implemented a code solution by initializing a loop and then filling in the details.
$dailyCount = array();
for( $i=1; $i<=30; $i++ ) {
$day = date('Y-m-d',(time()-($i*24*60*60)));
$dailyCount[$day] = 0;
}
foreach( $statement as $row ) {
$dailyCount[$row['d']] = $row['count'];
}
You can't do this with standard SQL queries - you'd be trying to group on a date(s) that doesn't exist in the table.
Standard workaround is to make a temporary table that contains the date range in sequential order with no gaps, join that against your table and do the count/aggregate as usual.
How can I group a query result by a field that is not saved in the database.
For example I want to group the result by duration which is came from subtraction of start time and end time.
here is how i find out the duration
date1= $row_TicketRS['CloseDate'];
$date2 = $row_TicketRS['OpenDate'];
$diff = abs(strtotime($date2) - strtotime($date1));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));
if ( $days > 0)
{
$time1 = $row_TicketRS['OpenTime'];
$time2= $row_TicketRS['CloseTime'];
$t1=($time1);
$t2=($time2);
$end=('14:30');
$start=('07:30');
$n = $end- $t1;
$n2 = $t2- $start;
$Hours2 = floor(($n+$n2)+(($days-1)*7));
echo $Hours2.' Hours';
but know i do not know how to add it to the query
here is my query
$strQuery = "SELECT count(`ticket`.TicketID) as TotOutput, department.`DeptName` FROM `ticket`, `user`, department where ticket.OwnerID = user.EmpNo and user.`DepartmentID` = department.`DepartmentID` and OpenDate between'".$DateFrom."' And '".$DateTo."'"
It'd be better to have details, but a derived table/inline view would allow you to group by a computed value:
SELECT x.duration,
COUNT(*)
FROM (SELECT t.col,
t.end_time - t.start_time AS duration
FROM YOUR_TABLE t) x
GROUP BY x.duration
How about adding that computed value to the query with an alias like this:
SELECT some_fields, end - start AS duration FROM table ORDER BY duration
dont put alias for hidden column , use directly
exmaple:
SELECT id, FLOOR(value/100)
FROM tbl_name
GROUP BY id, FLOOR(value/100);
Reference
MySQL permits expressions in GROUP BY
clauses, so the alias is unnecessary: