SQL Select data between date and hour in two columns - mysql

I have a SQL column like this:
| id | name | date | hour |
I want to select all names between specified start_date, start_hour and end_date, end_hour.
For data like this:
| 1 | one | 2014-12-29 | 11:00 |
| 2 | two | 2014-12-30 | 09:00 |
| 3 | three | 2014-12-30 | 11:00 |
Values:
start_date = 2014-12-29
start_hour = 11:00
end_date = 2014-12-30
end_hour = 10:00`
It should return: one, two.

This looks like a basic sql query. try the following:
select a.name
from (select * from data_table
where date >= start_date
and date <= end_date) as a
where a.hour >= start_hour
and a.hour <= end_hour
the basic idea is to first form a data set of all valid days for all times and then from there pull out the valid times. The other possibly more direct method would be to create a datetime field and then pull on that key.
Let me know if this works for you.

SELECT *
FROM table
WHERE date > '2014-12-28'
AND hour > '10:59'
AND date < '2014-12-31'
AND hour < '10:01'

Related

Mysql Subtract 'N' days to date value and compare to current date. N and Date are two column values

My table contains remind_me_befor_days column and expiry_date column.
I have to select records with condition (expiry_date - remind_me_befor_days) = current_date.
How this possible by query. Anyone can help me ?
Thanks in advance
You can do date arithemtics:
select t.*
from mytable t
where t.expiry_date - interval t.remind_me_befor_days day = current_date
Demo on DB Fiddle:
-- sample data
select * from mytable;
id | expiry_date | remind_me_befor_days
-: | :---------- | -------------------:
1 | 2019-12-25 | 10
2 | 2019-12-25 | 5
-- query
select t.*, current_date
from mytable t
where t.expiry_date - interval t.remind_me_befor_days day = current_date
id | expiry_date | remind_me_befor_days | current_date
-: | :---------- | -------------------: | :-----------
1 | 2019-12-25 | 10 | 2019-12-15
To split this into a few subproblems, we have:
Find the current date.
Subtract your remind_me_befor_days column value from the expiry_date column.
Use that as a filter for the records you want from the table.
The first can be done using the MySQL CURDATE() function. Read more here. Combining that with the second and third steps, you get something that looks like
SELECT *
FROM my_table
WHERE expiry_date - remind_me_befor_days = CURDATE()
I would strongly recommend that you write the condition as:
where expiry_date = curdate() + interval remind_me_before_days day
This is index friendly, so it can make use of an index on expiry_date.

MYSQL Select row when first part of condition is valid (with a group by)

I really don't know how to find an answer for my question, so I'm asking you.
Here is the table I have :
+----+------------+------------+-------------+
| id | start_date | end_date | id_person |
+----+------------+------------+-------------+
| 1 | 2017-10-01 | 2017-12-01 | 1 |
| 2 | 2017-07-01 | 2017-09-01 | 1 |
| 3 | 2016-01-01 | 2016-02-01 | 1 |
| 4 | 2016-05-01 | 2016-06-01 | 2 |
| 5 | 2016-01-01 | 2016-02-01 | 2 |
+----+------------+------------+-------------+
And here is the query I tried to use :
SELECT * FROM table
WHERE ((start_date < NOW() AND end_date > NOW())
OR start_date > NOW()
OR end_date < NOW())
GROUP BY `id_person`
The result I was expecting was this one :
+----+------------+------------+-------------+
| id | start_date | end_date | id_person |
+----+------------+------------+-------------+
| 2 | 2017-07-01 | 2017-09-01 | 1 | // matches first condition
| 4 | 2016-05-01 | 2016-06-01 | 2 | // matches 3rd condition and has the most recent start_date
+----+------------+------------+-------------+
If you didn't get what I did wrong yet, I'm going to tell you.
Here, I was trying to show a single row per person but I wanted this row to match the first condition it finds and not the others, I don't want the row to just be ordered by start_date. It is like a custom order where I want the first row for each person.
The problem is that this query doesn't work since the GROUP BY statement doesn't apply conditions first. (even if it did, I'm not sure the condition would only select one row)
I really don't know how I can achieve that and I don't even know if it is possible, I hope someone can lead me towards any solution.
Thanks for reading this, I'll answer as fast as I can to give you more informations.
Here's one idea...
SELECT m.*
FROM my_table m
JOIN
( SELECT x.id_person
, MAX(x.start_date) start_date
FROM my_table x
JOIN
( SELECT id_person
, MIN(CASE WHEN NOW() BETWEEN start_date AND end_date THEN 'A' WHEN start_date > NOW() THEN 'B' WHEN end_date < NOW() THEN 'C' END) rule
FROM my_table
GROUP
BY id_person
) y
ON y.id_person = x.id_person
AND y.rule = CASE WHEN NOW() BETWEEN start_date AND end_date THEN 'A' WHEN start_date > NOW() THEN 'B' WHEN end_date < NOW() THEN 'C' END
GROUP
BY id_person
) n
ON n.id_person = m.id_person
AND n.start_date = m.start_date;
+----+------------+------------+-----------+
| id | start_date | end_date | id_person |
+----+------------+------------+-----------+
| 2 | 2017-07-01 | 2017-09-01 | 1 |
| 4 | 2016-05-01 | 2016-06-01 | 2 |
+----+------------+------------+-----------+
If are happy to write the rules directly in sql rather than as where conditions you can ask the database for what yuo want more directly.
This means taking a step back to see what the rules you want are. It looks like you want to prioritise the entries by closest date, showing first current, then future, then historical. It also looks like end_date >= start_date, which means you only need to look at end_date to find what you are looking for.
Mysql can answer the question abusing it's group by functionality (until recent versions).
SELECT t.* FROM
(
SELECT t.*
FROM table t
ORDER BY SIGN(t.end_date - NOW()),ABS(t.end_date-NOW())
)
GROUP BY t.id_person
A standard sql method that will also play better with indexes would be to look for end dates before and after today separately.
SELECT t.*
FROM table t
JOIN (
SELECT t.person_id
,COALESCE(first_not_ended.end_date,t.last_ended.end_date) AS end_date
FROM table t
LEFT JOIN (
SELECT t.*,MIN(end_date) AS end_date
FROM table t
WHERE t.end_date > NOW()
GROUP by t.person_id
) first_not_ended
ON t.person_id=first_not_ended.person_id
AND t.end_date=first_not_ended.end_ate
LEFT JOIN (
SELECT t.person_id,MAX(end_date) AS end_date
FROM table t
WHERE t.end_date < NOW()
GROUP by t.person_id
) last_ended
ON t.person_id=last_ended.person_id
AND t.end_date=last_ended.end_date
) closest
ON t.person_id=closest.person_id
AND t.end_date=closest.end_date

SQL/Mysql Query available dates in database

I need some help querying my calendar/dates table
Scenario:
I have a "calendar" table with dates, user will set his available dates, usually day by day. So my table looks like this:
+------+------------+---------------------+---------------------+
| ID | user_id | start_date | end_date |
+------+------------+---------------------+---------------------+
| 1 | 1 | 2016-09-01 08:00:00 | 2016-09-01 16:00:00 |
| 2 | 1 | 2016-09-03 08:00:00 | 2016-09-03 16:00:00 |
| 3 | 1 | 2016-09-04 08:00:00 | 2016-09-04 16:00:00 |
| 3 | 1 | 2016-09-05 08:00:00 | 2016-09-05 16:00:00 |
+------+------------+---------------------+---------------------+
This means user 1 is available on the 1st, 3rd, 4th and 5th.
Lets say I want to query the table and find if user is available from date 2016-09-01 08:00:00 to 2016-09-05 16:00:00, this query must return zero rows since the user is not available on the 2nd of September. But if query from date 2016-09-03 08:00:00 to 2016-09-05 16:00: 00 then it will return these 3 rows.
Hope someone can help me with this
This could be one way (for a single user).
Note #endDate and #startDate are the supplied date fields to search.
SELECT
*
FROM your_table
WHERE EXISTS (
SELECT
user_id
FROM your_table
WHERE start_date >= #startDate
AND start_date <= #endDate
AND user_id = 1
GROUP BY user_id
HAVING SUM((DATEDIFF(end_date,start_date)+1)) = DATEDIFF(#endDate,#startDate)+1
)
AND start_date >= #startDate
AND start_date <= #endDate
AND user_id = 1
Note:
If the supplied date range falls within any range bounded by start_date and end_date (exclusive) then it won't work.
Since SUM((DATEDIFF(end_date,start_date)+1)) = DATEDIFF(#endDate,#startDate)+1 won't be equal in this case. Condition
In this case, you need to stay within the required boundary. Here the boundary is demarcated by the smaller value of end_date and #endDate and the larger value of start_date and #startDate.
Suppose, you have the following record (only one)
start_date = 2016-09-01 and end_date=2016-09-05.
And #startDate=2016-09-02 , #endDate=2016-09-04
Now check the above condition will fail for this set of data.
In this case you need to adopt the following query:
SELECT
*
FROM your_table
WHERE EXISTS (
SELECT
user_id
FROM your_table
WHERE end_date >= #startDate
AND start_date <= #endDate
AND user_id = 1
GROUP BY user_id
HAVING SUM((DATEDIFF(LEAST(end_date,#endDate),GREATEST(start_date,#startDate))+1)) = DATEDIFF(#endDate,#startDate)+1
)
AND end_date >= #startDate
AND start_date <= #endDate
AND user_id = 1
Assuming the periods in the table are not overlapping, you can count the number of days. The days in the period are then:
select sum(datediff(least($period_end, end_date),
greatest($period_start, start_date)
) + 1
)
from t
where $period_start <= end_date and
$period_end >= start_date;
You can then get a flag by comparing to the number of days:
select (case when sum(datediff(least($period_end, end_date),
greatest($period_start, start_date)
) + 1
) =
datediff($period_end, $period_start) + 1
then 1 else 0
end) as IsAvailableForAllDays
from t
where $period_start <= end_date and
$period_end >= start_date;

Select category between two date in mysql

I have this Table in mysql. I want to select data as "rc_type" between "start_date" & "end_date".
+----+--------+------------+------------+
| id | rc_type| start_date | end_date |
+----+--------+------------+------------+
| 1 | Gold | 16-05-2016 | 22-05-2016 |
| 2 | Silver | 20-05-2016 | 29-05-2016 |
+----+--------+------------+------------+
My html form has these three fields. So how to find rc_type?
I've tried this query:
SELECT * FROM room_inventory WHERE rc_type='silver' BETWEEN '16-05-2016' AND '17-05-2016'
And also:
SELECT * FROM room_inventory WHERE start_date >= '16-05-2016' AND end_date <= '17-05-2016' AND rc_type='Gold'
If I select start date as 16-05-2016 and end date as 17-05-2016 with "silver" category selection, I got result with "Gold" category. Actually there is no silver type between this two dates.
I don't get proper data. Kindly Help to get proper Data.
You need to separate presentation from real data type, i.e. is better to convert your date columns to real date format instead of varchar. However in order to get proper result you need to convert there strings to proper dates:
SELECT
*
FROM
room_inventory
WHERE
rc_type = 'Silver'
AND STR_TO_DATE(start_date, '%d-%m-%Y') > STR_TO_DATE('15-05-2016', '%d-%m-%Y')
AND STR_TO_DATE(end_date, '%d-%m-%Y') < STR_TO_DATE('30-05-2016', '%d-%m-%Y');
Output:
+----+---------+------------+------------+
| id | rc_type | start_date | end_date |
+----+---------+------------+------------+
| 2 | Silver | 20-05-2016 | 29-05-2016 |
+----+---------+------------+------------+
1 row in set
If you don't do such converts, you will get incorrect results as follow (I have changed Silver's end date to 29-06-2016):
Input:
mysql> select * from room_inventory;
+----+---------+------------+------------+
| id | rc_type | start_date | end_date |
+----+---------+------------+------------+
| 1 | Gold | 16-05-2016 | 22-05-2016 |
| 2 | Silver | 20-05-2016 | 29-06-2016 |
+----+---------+------------+------------+
2 rows in set
Query:
SELECT
*
FROM
room_inventory
WHERE
rc_type = 'Silver'
AND start_date > '15-05-2016'
AND end_date < '30-05-2016';
Output (wrong):
+----+---------+------------+------------+
| id | rc_type | start_date | end_date |
+----+---------+------------+------------+
| 2 | Silver | 20-05-2016 | 29-06-2016 |
+----+---------+------------+------------+
1 row in set
This is because MySQL performs char-by-char comparison and decides that 29-06-2016 < 30-05-2016 which is wrong. So in general you will have further problems if you keep dates columns in varchar format.
you are using wrong date format,
correct is year-month-day
also you had missing the date column in your query, in this example the query search silver category where start date between 2016-06-16 and 2016-05-17
SELECT * FROM room_inventory WHERE rc_type='silver' BETWEEN '2016-05-16' AND '2016-05-17'
#Danilo mentioned you are using wrong date format,
Another thing is your query formate of comparing date syntax is wrong.
correct syntax:
SELECT * FROM room_inventory WHERE rc_type='silver' AND Your Date BETWEEN '2016-05-16' AND '2016-05-17'.
But here you are comparing two dates so this query won't work as your expectation.
With second query please correct your date format as:
'SELECT * FROM room_inventory WHERE start_date >= '2016-05-16' AND end_date <= '2016-05-17' AND rc_type = 'Gold''
There is no need of 'between' try this:
SELECT * FROM room_inventory WHERE rc_type='silver' AND start_date = '16-05-2016' AND end_date = '17-05-2016'
Logical error , You are use between for two columns in a table. between is used to compare in between one columns ,so you can use AND instead of between .
SELECT * FROM room_inventory WHERE rc_type='silver' AND start_date = '16-05-2016' AND end_date = '17-05-2016'

Retrieve all records that occur within specific date range in MySQL

I have a table that contains several contracts, and each contract has a start date and an end date, like this:
| ID | Contract Name | Start Date | End Date |
|-------|-------------------|--------------|------------|
| 1 | Joe Bloggs | 2012-01-01 | 2012-02-05 |
| 2 | John Smiths | 2012-02-01 | 2012-02-20 |
| 3 | Johnny Briggs | 2012-03-01 | 2012-03-20 |
What I am trying to do is build a query that will retrieve contracts that were active between a specific time period. So if I had the start date of 2012-02-10 and an end date of 2012-03-21 I should have the following contracts displayed:
| ID | Contract Name | Start Date | End Date |
|-------|-------------------|--------------|------------|
| 2 | John Smiths | 2012-02-01 | 2012-02-20 |
| 3 | Johnny Briggs | 2012-03-01 | 2012-03-20 |
My problem though is that I don't know how to build the query to do this. This is what I've got so far:
SELECT *
FROM contracts c
WHERE c.startdate BETWEEN '2012-02-10'
AND '2012-03-21'
AND c.enddate BETWEEN '2012-02-10'
AND '2012-03-21'
This doesn't work though, no records are retrieved. What am I doing wrong?
SELECT * FROM contracts
WHERE (START_DATE between '2012-03-01' AND '2013-03-21')
OR (END_DATE between '2012-03-01' AND '2013-03-21')
OR (START_DATE<= '2012-03-01' AND END_DATE >='2013-03-21');
Check the SQL fiddle
Er, time is linear right?
SELECT *
FROM contracts
WHERE end_date >= '2012-02-10'
AND start_date <= '2012-03-21';
Let me illustrate...
A-------------B
<------->
<------>
<----------->
<---------------------->
In all cases above, the start date is less than B. The end date is greater than A.
For me, a good request will be
SELECT * FROM contracts c WHERE c.startdate >'2012-02-10' AND c.enddate < '2012-03-21'
It should have been like this
SELECT *
FROM contracts c
WHERE c.startdate >= '2012-02-10'
AND c.enddate <= '2012-03-21'
SELECT * FROM contracts
WHERE
(START_DATE between '2012-03-01' AND '2013-03-21')
OR (END_DATE between '2012-03-01' AND '2013-03-21')
OR (START_DATE<= '2012-03-01' AND END_DATE >='2013-03-21');
explanation:
(START_DATE between '2012-03-01' AND '2013-03-21')
: intervals records that start between the input dates. First part or all of interval might be included.
(END_DATE between '2012-03-01' AND '2013-03-21')
: intervals that end between the input dates. Last part or all of interval might be included.
(START_DATE<= '2012-03-01' AND END_DATE >='2013-03-21')
: input dates are included within one interval only