Mysql select dates that doesn't intersects with booked date ranges - mysql

I have a table of dates, each date represent a task, the task takes three days to complete.
I want to select all the unbooked dates that doesn't intersects with another booked task.
I've been trying and googling for three days now and I think it is time to ask for help.
date booked
=========== =======
2014-09-01 0
2014-09-02 1
2014-09-05 0
2014-09-10 1
2014-09-15 0
2014-09-16 0
2014-09-20 1
2014-09-25 0
The expected result:
date booked
=========== =======
2014-09-01 0
2014-09-15 0
2014-09-16 0
2014-09-25 0

You can use a left join (by adding 3 days in date column) with is null on same table to get the unbooked dates and doesnot intersects with other task's booked date
select t.*,
t1.date date1
from t
left join t t1 on(t.date = t1.date + interval 3 day)
where t.booked = 0 and t1.date is null
Fiddle Demo

Refer to the following answer.
Detect overlapping date ranges from the same table
If you could change date to Start_Date and add column End_Date (Start_Date + 3), then adding NOT to the answer quoted will result you in an answer that do not have overlapping date ranges.
select dr1.* from date_ranges dr1
inner join date_ranges dr2
where NOT (dr2.start > dr1.start -- start after dr1 is started
and dr2.start < dr1.end) -- start before dr1 is finished
From the results of the above query you can select the row which have 0 for booked column.

Related

MYSQL , Count week wise and also show sum with empty dates

I have two tables
Table_1 : Routes_Day_plan
Date Status_Id
------------------------
2019-06-09 1
2019-06-10 2
2019-06-09 2
2019-06-11 3
2019-06-14 4
2019-06-14 6
2019-06-15 8
Table_2 : Codes
id code
-------
1 Leave
2 Half_leave
3 Holiday
4 Work
5 Full_Hours
Now my task is to count week wise from table 1 where code (from second table) = Leave,Half_leave,work and than also show the sum , and where date not found show 0 , i write this query it's return data but not empty dates can someone please help ,
My Query:
select COUNT(*) as available, DATE(date)
from Table_1
where status_id in (
select id from codes
where code in ('Leave','Half_leave','work'))
AND DATE(date) >= DATE('2019-06-09') AND DATE(date) <= DATE('2019-06-16')
group by date
UNION ALL
SELECT COUNT(date), 'SUM' date
FROM Table_1
where status_id in (
select id from codes
where code in ('Leave','Half_leave','work'))
AND DATE(date) >= DATE('2019-06-09') AND DATE(date) <= DATE('2019-06-16')
Result Something Like ,
available Dates
------------------------
5 2019-06-09
2 2019-06-10
3 2019-06-11
3 2019-06-12
2 2019-06-14
2 2019-06-15
17 SUM
I want like this
available Dates
------------------------
5 2019-06-09
2 2019-06-10
3 2019-06-11
3 2019-06-12
0 2019-06-13
2 2019-06-14
2 2019-06-15
17 SUM
Your best bet here would be to have a Date Dimension/Lookup table which contains pre-populated dates for the entire year. By joining your record table to this lookup, you essentially allocate your data to each date that actually exist (ex. 2019-06-13) and if your data is not found in the lookup, you will find a null in that field.
The Count function will count a null as a 0. Just make sure you group on the date field from your lookup table and not from your record table.
Make a table, a date dimension that contains all the dates value, from beginning to end. Like this:
Set EndDate = '2099-01-01';
Set RunDate = '1900-01-01';
WHILE RunDate <= EndDate DO
insert into dim_date
(`DATE`)
select
RunDate as DATE
;
Set RunDate = ADDDATE(RunDate,1);
END WHILE;
Create temporary table with dim_date left join Routes_Day_plan and set Status as 0 maybe for record that dont match. Use this temporary table then instead of Routes_Day_plan in your queries.

Querying last two days depending on a Workday or not table

We use Mysql and we're trying to get averages from last two workdays from a hourly data set like this.
Date Price
2016-12-13 00:00 187,68
2016-12-13 01:00 201
2016-12-13 02:00 211,66
2016-12-13 03:00 215,84
So we created a table named (Workdays) that shows if the day is a workday or holiday like this:
Date Workday
2016-12-13 1
2016-12-14 1
2016-12-15 0
2016-12-16 0
1 means workday and 0 means weekend or National Holiday
At the and, we have to query Average price of the last two workdays seperately considering Workdays table
Is this possible?
Thanks a lot.
If I understand correctly, the table workdays really has a single row for each date. If so, you can get the most recent two workdays in a subquery and then use join to choose the rows in the first table:
select wd.date, avg(h.Price)
from hourly h join
(select wd.date
from workdays wd
where wd.workday = 1 and wd.date <= curdate() -- you might want <
order by wd.date desc
limit 2
) wd2
on date(h.date) = wd.date
group by wd.date;
try this
select W.Date, AVG(Price)
from Prices p
join Workdays W on
w.Date = DATE(P.Date)
AND Workday=1
and W.Date <= curdate()
group by W.Date
order by W.Date desc;

Calculating 'on time performance' between scheduled and actual times

I have a table of scheduled times for an event and a second of actual times the event happened, for example:
Table A
ID Date Scheduled
1 2014-09-01 07:05:00
2 2014-09-02 07:05:00
3 2014-09-03 08:05:00
4 2014-09-04 07:10:00
Table B
ID Date Actual
1 2014-09-01 07:10:00
2 2014-09-02 07:16:00
3 2014-09-03 08:00:00
4 2014-09-04 14:15:00
If we assume that anything within 10 minutes of schedule is considered 'on time', is there a way to return the 'on time performance' using MySQL? In the data set above, the on time performance would be 50%, since two of the events happened within 10 minutes of the schedule.
Supplementary edit: If an event is early, that would also be considered on time
Yes. However, I don't understand why the date and time are in different columns. You just need to join the two tables together and do some conditional logic:
select avg(case when a.date = b.date and a.actual <= a.scheduled + interval 10 minute then 1
when b.date < a.date then 1
else 0
end) as OnTimePerformance
from tablea a join
tableb b
on a.id = b.id;
This doesn't handle the case where an event is scheduled on one day (say 11:55 p.m.) and the actual time is the next day (12:01 a.m.). Your data suggests this does not happen. This condition would be easier if the date and time were in a single column.
Here is another way of doing it
select
round((on_time/tot)*100) as performance
from
(
select
count(*) as tot,
sum(
case when
timestampdiff(minute,concat(t1.Date,' ',t1.Scheduled),concat(t2.Date,' ',t2.Actual)) < 10
then 1
end
) as on_time
from tableA t1
join tableB t2 on t1.id = t2.id
)p;
DEMO

Group by week returning strange intervals

For some odd reason, group by week is returning odd date intervals with a datetime field.
"Completed" is a datetime field, and using this query:
SELECT
Completed,
COUNT( DISTINCT Table1.ID ) AS ActivityCount
FROM Table1
JOIN Table1Items
ON Table1.ID = Table1Items.ID
JOIN database_database.Table2
ON Table2.Item = Table1Items.Item
WHERE Completed != '0000-00-00' AND Completed >= '2012-09-25' AND Completed <= '2012-10-25'
GROUP BY WEEK(Completed)
I'm getting:
Completed ActivityCount CompletedTimestamp
2012-09-25 300 2012-09-25 00:00:00
2012-10-02 764 2012-10-02 00:00:00
2012-10-08 379 2012-10-08 00:00:00
2012-10-17 659 2012-10-17 00:00:00
2012-10-22 382 2012-10-22 00:00:00
some are 7 days apart, others are 6 days apart, others are 5.... and one is 9?
Why does it group the dates by such strange intervals instead of just 7 days?
The week function does not count the difference of the dates.
The week function returns the week number of a date. If you group by it, then in the group will be dates at the start and end of the week and in bettween. The difference betwween the single dates can be greater than 7 days or less.
The answer, as alluded to by juergen d, was to aggregate the date column -- use min or max depending on whether you want to the first day or last day of the week used as the consistent interval; e.g.:
SELECT MIN(Completed), COUNT( DISTINCT Table1.ID ) AS ActivityCount FROM Table1 JOIN Table1Items ON Table1.ID = Table1Items.ID JOIN database_database.Table2 ON Table2.Item = Table1Items.Item WHERE Completed != '0000-00-00' AND Completed >= '2012-09-25' AND Completed <= '2012-10-25' GROUP BY WEEK( Completed)

Mysql query with criteria value > 10 for consecutive date period of 3 hours

Consider a table with id,date datetime,value double, I have data in the table every minute.
I'm trying to use mysql to identify "events" where value > 10 continuously for more than 3 hours.
At the time I am using the query:
select date from table where value > 10;
Then I manually read where the dates are continuously.
Example of "event":
Date - value
2000/01/01 00:00 - 5
2000/01/01 01:00 - 5
2000/01/01 02:00 - 5
2000/01/01 03:00 - 11
2000/01/01 04:00 - 11
2000/01/01 05:00 - 11
2000/01/01 06:00 - 5
2000/01/01 07:00 - 5
2000/01/01 08:00 - 5
2000/01/01 09:00 - 11
2000/01/01 10:00 - 11
2000/01/01 11:00 - 5
In this case there is one "event" between 03:00 and 05:00.
In MySQL, you can assign variables in a SELECT statement while retrieving data. This functionality helps in solving many problems where one would "normally" use windowing functions (which MySQL doesn't have). It can also help in yours. Here's a solution I ended up with:
SET #startdate = CAST(NULL AS datetime);
SET #granularity = 60; /* minutes */
SET #minduration = 180; /* minutes */
SET #minvalue = 10;
SELECT
t.Date,
t.Value
FROM (
SELECT
StartDate,
MAX(Date) AS EndDate
FROM (
SELECT
Date,
Value,
CASE
WHEN Value > #minvalue OR #startdate IS NOT NULL
THEN IFNULL(#startdate, Date)
END AS StartDate,
#startdate := CASE
WHEN Value > #minvalue
THEN IFNULL(#startdate, Date)
END AS s
FROM (
SELECT Date, Value FROM YourTable
UNION ALL
SELECT MAX(Date) + INTERVAL #granularity MINUTE, #minvalue FROM YourTable
) s
ORDER BY Date
) s
WHERE StartDate IS NOT NULL
GROUP BY StartDate
) s
INNER JOIN YourTable t ON t.Date >= s.StartDate AND t.Date < s.EndDate
WHERE s.EndDate >= s.StartDate + INTERVAL #minduration MINUTE
;
Three of the four variables used here are merely script arguments, and only one, #startdate, actually gets both assigned and checked in the query.
Basically, the query iterates over the rows, marking those where the value is greater than a specific minimum (#minvalue), eventually producing a list of time ranges during which values matched the condition. Actually, in order to calculate the ending bounds correctly, non-matching rows that immediately follow groups of the matching ones are also included in the respective groups. Because of that, an extra row is being added to the original dataset, where Date is calculated off the latest Date plus the specified #granularity of timestamps in your table and Value is just #minvalue.
Once obtained, the list of ranges is joined back to the original table to retrieve the detail rows that fall in between the ranges' bounds, the ranges that are not long enough (as specified by #minduration) being filtered out along the way.
If you run this solution on SQL Fiddle, you will see the following output:
DATE VALUE
------------------------------ -----
January, 01 2000 03:00:00-0800 11
January, 01 2000 04:00:00-0800 11
January, 01 2000 05:00:00-0800 11
which, I understand, is what you would expect.
select count(*) from table where DATE_SUB(CURDATE(),INTERVAL 3 HOUR) < `date`
select count(*) from table where DATE_SUB(CURDATE(),INTERVAL 3 HOUR) < `date` AND `value` > 10
Then compare the result, if not same, then is not continuously.
Wild guess:
select * from
(select event, MAX(date) as date from table where value > 10 group by event) maxs
inner join
(select event, MIN(date) as date from table where value > 10 group by event) mins
on maxs.event = mins.event
where (time_to_sec(timediff(maxes.date, mins.date)) / 3600) > 3