SQL - Query for a meeting room - mysql

I need a help to create a query to return if the period selected already has a meeting in the room.
I have table rep_reuniao with the following design
ID --> int
ROOM --> int
DATE_BEGIN --> DATETIME
DATE_END --> DATETIME
Now an insert of a row in the table rep_reuniao looks like this
ID --> 1
ROOM --> 2
DATE_BEGIN --> 2014-02-21 17:00:00
DATE_END --> 2014-02-21 18:00:00
I will create an Jquery Ajax script to return a true or false JSON response based on the selected datetime.
So the query will have the ROOM, DATE_BEGIN in this format 2014-02-21 17:00 and DATE_END in the same format 2014-02-21 18:00
I Have checked another responses, but the most of them is a query to show the Rooms available. In my desing, a room is always available, except when exist a register in the table.
Example 1
ROOM 1 is already in use from 2014-02-21 17:00:00 to 2014-02-21 18:00:00
Need create a query to return a value (Anything) if the user select a room in:
BEGIN = 2012-02-21 16:30:00
END = 2012-02-21 17:30:00
See? The room in use in the table begins 17:00 so today my query easly return a value if the begin selected by the user is the same. But the End date selected by the user is between the time already in use.
Well, the selected time by the user cannot be in use lookin into the begin date and end date. I have no ideas right now, anyone can help me?
You need to check if one date range overlaps another date range.
New Date Range = |-----------|
Test1 = |=====|
Test2 = |=====|
Test3 = |=====|
Test4 = |=====|
Test5 = |=====|
Test6 = |=================|
Only Test1 and Test5 do not overlap.
Sorry if has any English errors. If someone are able to fix, I'll appreciate.

The correct logic over overlapping timeframes is that two time frames overlap when both these conditions are true:
the first starts before the other ends
the first ends after the other starts
In SQL, these can be expressed easily:
SELECT r.*
FROM rep_reuniao r
WHERE #UserBegin <= r.DATE_END AND
#UserEnd >= r.DATE_BEGIN;
Note that this can return multiple rows, when multiple meetings occur during the specified timeframe.
If you want true/false or 0/1, then use aggregation and case:
SELECT (case when count(*) = 0 then 'false' else 'true' end) as HasOverlappingRooms
FROM rep_reuniao r
WHERE #UserBegin <= r.DATE_END AND
#UserEnd >= r.DATE_BEGIN;

Try this, if the query returns any rows that means the room is already booked.
A simple explanation is the user gives #UserBegin and #UserEnd time that they need the room for.
And if the #UserBegin is between a row's begin and end then it is already booked.
Similarly, if the #UserEnd is between a row's begin and end, even then the room is booked.
SELECT *
FROM rep_reuniao r
WHERE (#UserBegin BETWEEN r.DATE_BEGIN AND r.DATE_END)
OR (#UserEnd BETWEEN r.DATE_BEGIN AND r.DATE_END)
OR (#UserBegin <= r.DATE_BEGIN AND #UserEnd >= r.DATE_END)
From here you can extend this to return a bool like shown
SELECT CASE WHEN EXISTS ( /* The above query */ ) THEN 0 ELSE 1
This should return 1 or 0, when the room is available or not respectively.

You could try the following query. It should catch when a date in the table falls within your range, or when you range falls within a date in the table:
SELECT CASE WHEN COUNT(*) > 1 THEN 1 ELSE 0 END AS AlreadyBooked
FROM rep_reuniao r
WHERE (#UserBegin BETWEEN r.DATE_BEGIN AND r.DATE_END)
OR (r.DATE_BEGIN BETWEEN #UserBegin AND #UserEnd)
The query checks for any rows where either #UserBegin falls within the range in the row or where the row's start date falls withing #userBegin - #UserEnd. It will find cases where the ranges partially overlap, or where either range falls within the other.

Related

how to shift back the date by a certain number of days v2

I have the following problem: I have a table in which in the first column there are dates, in the second information whether a day is a working day or not (1 or 0) and in the third, the number of working days by which the value from the first column should be shift back. Anyone have maybe think how to get this fourth column?
The table looks something like this:
date
workday
days back
10.01.2021
1
1
10.01.2021
1
2
10.01.2021
1
3
10.01.2021
1
4
11.01.2021
0
1
11.01.2021
0
2
11.01.2021
0
3
11.01.2021
0
4
12.01.2021
1
1
12.01.2021
1
2
12.01.2021
1
3
12.01.2021
1
4
or otherwise .... the third column is the number of working days needed to make a given product. The first column is the date when the product have to be ready.
I need in column nr 4 the date (the working day) in which to start production. For example for line 9 it will be 10.012021 This view is supposed to be a combination of product realization dates and production start dates for different production lifecycle values.
You either need every working day in your table or you need a separate table with a every day and whether it is a working day or not.
I'm not familiar with mysql, the below is my attempt to translate something that works in MS SQL Server, I'm hoping it will work in mysql.
Below I've assumed your only table is called Table1 and it has every working day in and is the table from your question.
First you need to create a function
CREATE FUNCTION [OffsetDate]
(
#StartDate DATE NULL,
#OffsetDays INT = 0
)
RETURNS DATE
AS
BEGIN
DECLARE #Result DATE
SET #Result = #StartDate
BEGIN
SELECT #Result = distinctDates.Date
FROM (SELECT DISTINCT Table1.Date
FROM Table1
WHERE Table1.Date <= #StartDate
AND Table1.WorkDay = 1) AS distinctDates
ORDER BY distinctDates.Date DESC
LIMIT 1 OFFSET #OffsetDays
END
RETURN #Result
END
Then use this in a query to get your 4th column:
SELECT Table1.Date, Table1.WorkDay, Table1.[Days Back], OffsetDate(Table1.Date, Table1.[Days Back]) AS StartDate
FROM Table1

How to store date and time ranges without overlap in MySQL

I'm trying to find the right query to check if date and time ranges overlap in the MySQL table, here is the table:
id pickup_date pickup_time return_date return_time
1 2016-05-01 12:00:00 2016-05-31 13:00:00
2 2016-07-01 12:00:00 2016-07-04 15:00:00
Here are the data about every reservation which is coming and need to be checked against the "Reservations" table:
pickup_date = '2016-04-01';
pickup_time = '12:00:00'
return_date = '2016-05-01';
return_time = '13:00:00'
with this data the reservation overlap the one in the database. Take a note: the new reservation can be in the past or in the future.
EDIT (as proposed by spencer7593, this is the working version so far):
SET #new_booking_pickup_date = '2016-04-01';
SET #new_booking_pickup_time = '12:00:00';
SET #new_booking_return_date = '2016-05-01';
SET #new_booking_return_time = '13:00:00';
SELECT * FROM Reservation WHERE NOT
( CONCAT(#new_booking_pickup_date,' ',#new_booking_pickup_time) > CONCAT(return_date,' ',return_time) + INTERVAL 0 DAY OR CONCAT(#new_booking_return_date,' ',#new_booking_return_time) < CONCAT(pickup_date,' ',pickup_time) + INTERVAL 0 DAY);
, so this query will result:
id pickup_date pickup_time return_date return_time
1 2016-05-01 12:00:00 2016-05-31 13:00:00
It's pretty easy to determine if a given period doesn't overlap with another period.
For ease of expressing the comparison, for period 1, we'll let the begin and end be represented by b1 and e1. For period 2, b2 and e2.
There is no overlap if the following is true:
b1 > e2 OR e1 < b2
(We can quibble whether equality of b1 and e2 would be considered an overlap or not, and adjust as necessary.)
The negation of that test would return TRUE if there was an overlap...
NOT (b1 > e2 OR e1 < b2)
So, to find out if there is a row that overlaps with the proposed period, we would need a query that tests whether a row is returned...
Let's assume that table we are going to check has columns st and et (DATETIME) representing the beginning and ending of each period.
To find rows with an overlap with a proposed period bounded by b1 and e1
SELECT t.* FROM t WHERE NOT (b1 > t.et OR e1 < t.st)
So for a query to just check for the existence of an overlapping row, we could do something like this:
SELECT EXISTS (SELECT 1 FROM t WHERE NOT (b1 > t.et OR e1 < t.st))
That's pretty simple.
It's going to look a lot more complicated when we make the adjustment for the (inexplicable) split of the date and time components of a datetime into separate columns (as shown in the question).
It's just a straightforward matter of combining the separate date and time values together into a single value of DATETIME datatype.
All we need to do is substitute into our query above an appropriate conversion, e.g.
st => CONCAT(pickup_date,' ',pickup_time) + INTERVAL 0 DAY
et => CONCAT(return_date,' ',return_time) + INTERVAL 0 DAY
Same for b1 and e1.
Doing that substitution, coming up with the final query, is left as an exercise for whoever decided that storing date and time as separate columns was a good idea.

How to compare 1 set of date with another set of date in SQL Server for overlapping period

I have two sets of dates. I need to check whether the set A dates overlap on Set B dates in SQL Server
What is the best approach?.
Set A: (MM/DD/YYYY)
Date from: 1/1/2013
Date To: 2/15/2013
Set B (MM/DD/YYYY)
Date From : 2/10/2013
Date To : 2/20/2013
UPDATE
It's a leave application, where if an employee applies leave, I need to check whether the from and to date over laps on any other pending/Approved leave for the same employee. before letting the employee apply his leave.
Given two date ranges (A and B) you can test whether they overlap by checking if A starts before B finishes and A finishes after B starts. Depending on your data, it should be fairly simple to do this in SQL:
If Exists
(
SELECT 1
FROM LeaveTable
WHERE State In ('Pending', 'Approved')
And #ProposedStart < EndDate
And #ProposedEnd > StartDate
)
BEGIN
RAISERROR('The proposed leave overlaps.', 16, 1);
Return;
END;

MySQL query to select events between start/end date

I have a MySQL table named 'events' that contains event data. The important columns are 'start' and 'end' which contain string (YYYY-MM-DD) to represent when the events starts and ends.
I want to get the records for all the active events in a time period.
Events:
------------------------------
ID | START | END |
------------------------------
1 | 2013-06-14 | 2013-06-14 |
2 | 2013-06-15 | 2013-08-21 |
3 | 2013-06-22 | 2013-06-25 |
4 | 2013-07-01 | 2013-07-10 |
5 | 2013-07-30 | 2013-07-31 |
------------------------------
Request/search:
Example: All events between 2013-06-13 and 2013-07-22 : #1, #3, #4
SELECT id FROM events WHERE start BETWEEN '2013-06-13' AND '2013-07-22' : #1, #2, #3, #4
SELECT id FROM events WHERE end BETWEEN '2013-06-13' AND '2013-07-22' : #1, #3, #4
====> intersect : #1, #3, #4
Example: All events between 2013-06-14 and 2013-06-14 :
SELECT id FROM events WHERE start BETWEEN '2013-06-14' AND '2013-06-14' : #1
SELECT id FROM events WHERE end BETWEEN '2013-06-14' AND '2013-06-14' : #1
====> intersect : #1
I tried many queries still I fail to get the exact SQL query.
Don't you know how to do that? Any suggestions?
Thanks!
If I understood correctly you are trying to use a single query, i think you can just merge your date search toghter in WHERE clauses
SELECT id
FROM events
WHERE start BETWEEN '2013-06-13' AND '2013-07-22'
AND end BETWEEN '2013-06-13' AND '2013-07-22'
or even more simply you can just use both column to set search time filter
SELECT id
FROM events
WHERE start >= '2013-07-22' AND end <= '2013-06-13'
You need the events that start and end within the scope. But that's not all: you also want the events that start within the scope and the events that end within the scope. But then you're still not there because you also want the events that start before the scope and end after the scope.
Simplified:
events with a start date in the scope
events with an end date in the scope
events with the scope startdate between the startdate and enddate
Because point 2 results in records that also meet the query in point 3 we will only need points 1 and 3
So the SQL becomes:
SELECT * FROM events
WHERE start BETWEEN '2014-09-01' AND '2014-10-13'
OR '2014-09-01' BETWEEN start AND end
Here lot of good answer but i think this will help someone
select id from campaign where ( NOW() BETWEEN start_date AND end_date)
SELECT id
FROM events
WHERE start <= '2013-07-22'
AND end >= '2013-06-13';
Or use MIN() and MAX() if you don't know the precedence.
SELECT *
FROM events
WHERE start <= '2013-07-22' OR end >= '2013-06-13'
SELECT *
FROM events
WHERE endDate >= #startDate AND startDate <= #endDate
For explanation refer to this diagram:
Suppose sample data is [startDate: 2020-10-01, endDate: 2020-20-01]
The user provides #startDate and #endDate to search
For overlap there are 4 scenarios and 1 variation (red/maroon lines)
For no overlap there are just 2 scenarios (green lines)
So, in order to get overlapping dates by providing start and end date, endDate must be greater than #startDate and startDate must be less than #endDate.
EDIT: I've squeezed the filter a lot. I couldn't wrap my head around it before how to make sure something really fit within the time period. It's this: Start date BEFORE the END of the time period, and End date AFTER the BEGINNING of the time period
With the help of someone in my office I think we've figured out how to include everyone in the filter.
There are 5 scenarios where a student would be deemed active during the time period in question:
1) Student started and ended during the time period.
2) Student started before and ended during the time period.
3) Student started before and ended after the time period.
4) Student started during the time period and ended after the time period.
5) Student started during the time period and is still active (Doesn't have an end date yet)
Given these criteria, we can actually condense the statements into a few groups because a student can only end between the period dates, after the period date, or they don't have an end date:
1) Student ends during the time period AND [Student starts before OR during]
2) Student ends after the time period AND [Student starts before OR during]
3) Student hasn't finished yet AND [Student starts before OR during]
(
(
student_programs.END_DATE >= '07/01/2017 00:0:0'
OR
student_programs.END_DATE Is Null
)
AND
student_programs.START_DATE <= '06/30/2018 23:59:59'
)
I think this finally covers all the bases and includes all scenarios where a student, or event, or anything is active during a time period when you only have start date and end date. Please, do not hesitate to tell me that I am missing something. I want this to be perfect so others can use this, as I don't believe the other answers have gotten everything right yet.
try this
SELECT id FROM events WHERE start BETWEEN '2013-06-13' AND '2013-07-22'
AND end BETWEEN '2013-06-13' AND '2013-07-22'
DEMO HERE
output :
ID
1
3
4
If you would like to use INTERSECT option, the SQL is as follows
(SELECT id FROM events WHERE start BETWEEN '2013-06-13' AND '2013-07-22')
INTERSECT
(SELECT id FROM events WHERE end BETWEEN '2013-06-13' AND '2013-07-22')
In PHP and phpMyAdmin
$tb = tableDataName; //Table name
$now = date('Y-m-d'); //Current date
//start and end is the fields of tabla with date format value (yyyy-m-d)
$query = "SELECT * FROM $tb WHERE start <= '".$now."' AND end >= '".$now."'";
If anyone is searching for a situation when the current date is residing between two periods (start/end date) in Microsoft SQL, please find below
select id from campaign where (getdate() BETWEEN start_date AND end_date)

Using DatePart() with date ranges crossing the datepart boundary

I am currently trying to summarise some data tables into a report. Each record in the table consists of a date range, something like this:
StartDate EndDate
--------------------
13/04/13 15/04/13
17/04/13 24/04/13
28/04/13 03/05/13
05/05/13 10/05/13
Assuming the date ranges signify something like days of leave, I want to be able to calculate the total amount of days of leave per month. I came across the DatePart function which seems to work apart from one edge case: when the date range crosses a month boundary. Since the DatePart function returns the month for one given date, I am no longer able to use that to determine the amount of days of leave for that edge case record (in the example above it is record 3), since it applies to two separate months.
Ideally I want my final table to look like:
Month #OfDays
--------------------
4 11 (1st record - 2, 2nd record - 7, 3rd record - 2)
5 8 (3rd record - 3, 4th record - 5)
I've considered some messy options, such as populating a temporary table having each record signifying a different day and then doing a query on that, but I am not sure how this ties in with a report. Right now my report record source is the (incorrect) query, is it possible to have a record source as a VBA function that returns a recordsource?
Another thing I thought was to possibly to have an initial query that splits up any edge cases into two seperate records, where the date range only covers one month, and then use that for my final grouping query. Is that even possible?
I feel there may be a much simpler solution to this problem yet I can't see it.
If anyone has any ideas it would be much appreciated!
To accomplish your task using Access queries you will need to create a table named [Numbers] with a single Number (Long Integer) column named [n] containing the numbers 1, 2, 3, ... up to the highest year you expect to be working with. I created mine as follows
n
----
1
2
3
...
2499
2500
You'll also need to paste the following VBA function into an Access Module
Public Function IsValidDayOfYear(YearValue As Long, DayValue As Long) As Boolean
Dim IsLeapYear As Boolean
If (YearValue Mod 400) = 0 Then
IsLeapYear = True
ElseIf (YearValue Mod 100) = 0 Then
IsLeapYear = False
ElseIf (YearValue Mod 4) = 0 Then
IsLeapYear = True
Else
IsLeapYear = False
End If
IsValidDayOfYear = (DayValue <= IIf(IsLeapYear, 366, 365))
End Function
Let's assume that your source table is called [DateRanges]. We'll start by creating a query that generates every day of the year for each year represented in the source table. The trick here is that DateSerial() "rolls over" month boundaries, so
DateSerial(2013, 1, 32) = #2013-02-01#
and
DateSerial(2013, 1, 234) = #2013-08-22#
SELECT DateSerial(yr.n, 1, dy.n) AS [Date]
FROM Numbers yr, Numbers dy
WHERE
(
yr.n
BETWEEN (SELECT MIN(DatePart("yyyy", DateRanges.StartDate)) FROM DateRanges)
AND (SELECT MAX(DatePart("yyyy", DateRanges.EndDate)) FROM DateRanges)
)
AND (dy.n < 367) AND IsValidDayOfYear(yr.n, dy.n)
For your sample data, that query returns all days in 2013.
Let's save that query as [AllDays]. Now we can use it to extract the individual days for each date range (omitting StartDate so the final counts match yours in the question)
SELECT [Date] FROM AllDays
WHERE EXISTS
(
SELECT * FROM DateRanges
WHERE AllDays.[Date] BETWEEN DateAdd("d", 1, DateRanges.StartDate) AND DateRanges.EndDate
)
That returns the individual days corresponding to each range, i.e.,
Date
----------
2013-04-14
2013-04-15
2013-04-18
2013-04-19
2013-04-20
2013-04-21
2013-04-22
2013-04-23
2013-04-24
2013-04-29
2013-04-30
2013-05-01
2013-05-02
2013-05-03
2013-05-06
2013-05-07
2013-05-08
2013-05-09
2013-05-10
We can save that query as [RangeDays] and then use it to calculate our counts by month...
SELECT DatePart("m", [Date]) AS [Month], COUNT(*) AS NumOfDays
FROM RangeDays
GROUP BY DatePart("m", [Date])
...returning
Month NumOfDays
----- ---------
4 11
5 8