select data from mysql using two column ranges - mysql

I have data like this
sno name date time
1 Irona 2016-01-01 10:00:00
2 Meona 2016-01-02 21:00:00
3 Lessa 2016-01-02 8:00:00
4 Airik 2016-01-03 10:00:00
I m trying query like this
SELECT * FROM `appointment` where (date <= '2016-01-02' and time >= '21:00:00') and (date >= '2016-01-03' and time >= '10:00:00')
I want those appointment which are between 2016-01-02 and 2016-01-03 and also between 9 pm to 10 am

Try this:
SELECT *
FROM `appointment` A
WHERE STR_TO_DATE(CONCAT(A.date, ' ', A.time), '%Y-%m-%d %H:%i:%s') BETWEEN '2016-01-02 21:00:00' AND '2016-01-03 10:00:00'

Query date <= '2016-01-02' and date >= '2016-01-03' returns nothing.
you should change it to date >= '2016-01-02' and date <= '2016-01-03'
SELECT * FROM `appointment`
where date >= '2016-01-02' and date <= '2016-01-03'
and time <= '21:00:00' and time >= '10:00:00'

I will do it like this:
...
WHERE
to_char(date, '%Y%m%d') between '20160102' and '20160103'
AND to_char(timedate, '%H') between '10' and '21'

Related

Find gaps in SQL between datetime Ranges within a startdatetime and enddatetime value

im looking for a SQL Query that can deliver me all of the free time Intervals between a given Range for a Table with two datetime Columns (DATE_FROM, DATE_TILL). As a Requirement: All other entries are not overlapped and the only acceptable distance between each interval is 1 Second.
I have found a Solution but this doesnt fill all my Requirements, specially the one where i want to put a given start and end datetime to calculate the missing Intervals if given.
Here is my datatable:
ROW_ID LOCATION_ID DATE_FROM DATE_TILL
1 193 2019-02-01 00:00:00 2019-12-31 23:59:59
2 193 2020-02-01 00:00:00 2020-12-31 23:59:59
3 193 2021-01-01 00:00:00 2021-12-31 23:59:59
4 193 2022-01-01 00:00:00 2022-12-31 23:59:59
5 204 2020-01-01 00:00:00 2021-12-31 23:59:59
And this is my SQL Query, which is from another Solution in this Plattform where i made some requirements changes.
SELECT DATE_ADD(DATE_TILL,INTERVAL 1 SECOND) AS GAP_FROM, DATE_SUB(DATE_FROM,INTERVAL 1 SECOND) AS GAP_TILL
FROM
(
SELECT DISTINCT DATE_FROM, ROW_NUMBER() OVER (ORDER BY DATE_FROM) RN
FROM overlappingtable T1
WHERE
LOCATION_ID = 193 AND
NOT EXISTS (
SELECT *
FROM overlappingtable T2
WHERE T1.DATE_FROM > T2.DATE_FROM AND T1.DATE_FROM < T2.DATE_TILL
)
) T1
JOIN (
SELECT DISTINCT DATE_TILL, ROW_NUMBER() OVER (ORDER BY DATE_TILL) RN
FROM overlappingtable T1
WHERE
LOCATION_ID = 193 AND
NOT EXISTS (
SELECT *
FROM overlappingtable T2
WHERE T1.DATE_TILL > T2.DATE_FROM AND T1.DATE_TILL < T2.DATE_TILL
)
) T2
ON T1.RN - 1 = T2.RN
WHERE
DATE_ADD(DATE_TILL,INTERVAL 1 SECOND) < DATE_FROM
This Query delivers me this result:
GAP_FROM GAP_TILL
2020-01-01 00:00:00 2020-01-31 23:59:59
Which is great, this is the free Interval that i have to deliver between entries that have their ranges and dont overlap.
But I want to set in this Query two Parameters for The Main Range for this entries. One for the startdate and the other for enddate. For this example:
startdate = '2019-01-01 00:00:00'
enddate = '9999-12-31 23:59:59'
For LOCATION_ID = 193 i am missing the gap between the startdate('2019-01-01 00:00:00') and the first DATE_FROM for the first entry('2019-02-01 00:00:00').
The result that i would like to deliver should look like this for LOCATION_ID = 193:
GAP_FROM GAP_TILL
2019-01-01 00:00:00 2019-01-31 23:59:59
2020-01-01 00:00:00 2020-01-31 23:59:59
2023-01-01 00:00:00 9999-12-31 23:59:59
Im really new at SQL and could understand this Query, but i can't develop this further to set these Main Ranges and deliver the missing gaps.
Thanks in Advance
For clarity I would recommend to find the initial gaps, the middle ones, and the ending ones in separate CTEs, as shown below in the b, m, and e CTEs. Then, a simple UNION ALL can combine all of them:
with
p (loc_id, start_date, end_date) as (
select 193, '2019-01-01 00:00:00', '9999-12-31 23:59:59'
),
r as (
select location_id, date_from,
date_add(date_till, interval 1 second) as date_till,
lead(date_from) over(partition by location_id order by date_from) as next_from
from overlappingtable t
cross join p
where t.location_id = p.loc_id
),
b as (
select p.start_date as gap_from, r.date_from as gap_till
from (select * from r order by date_from limit 1) r
cross join p
where p.start_date < r.date_from
),
m as (
select date_till, next_from
from r
where date_till < next_from
),
e as (
select r.date_till, p.end_date
from (select * from r order by date_till desc limit 1) r
cross join p
where r.date_till < p.end_date
)
select * from b
union all select * from m
union all select * from e
order by gap_from
Result:
gap_from gap_till
-------------------- -------------------
2019-01-01 00:00:00 2019-02-01 00:00:00
2020-01-01 00:00:00 2020-02-01 00:00:00
2023-01-01 00:00:00 9999-12-31 23:59:59
See running example atDB Fiddle.
The initial CTE p includes the parameters of the query (loc_id, start_date, end_date) and is added for clarity.
You could join to a sub-query with the start & end datetimes.
Then compare to the previous & next datetimes per location_id.
The previous or next datetimes can be found via the LAG & LEAD functions.
WITH CTE_UNDERLAPS AS
(
SELECT t.*
, LAG(DATE_TILL) OVER (PARTITION BY LOCATION_ID ORDER BY DATE_FROM, DATE_TILL) AS PREV_DATE_TILL
, LEAD(DATE_FROM) OVER (PARTITION BY LOCATION_ID ORDER BY DATE_FROM, DATE_TILL) AS NEXT_DATE_FROM
, l.*
FROM overlappingtable t
JOIN (
SELECT
CAST('2019-01-01 00:00:00' AS DATETIME) AS START_DATETIME
, CAST('9999-12-31 23:59:59' AS DATETIME) AS END_DATETIME
) l ON DATE_FROM >= START_DATETIME AND DATE_TILL <= END_DATETIME
)
SELECT LOCATION_ID
, COALESCE(DATE_ADD(PREV_DATE_TILL,INTERVAL 1 SECOND), START_DATETIME) AS DATE_FROM
, DATE_SUB(DATE_FROM,INTERVAL 1 SECOND) AS DATE_TILL
FROM CTE_UNDERLAPS
WHERE COALESCE(DATE_ADD(PREV_DATE_TILL,INTERVAL 1 SECOND), START_DATETIME) < DATE_FROM
UNION
SELECT LOCATION_ID
, DATE_ADD(DATE_TILL,INTERVAL 1 SECOND) AS DATE_FROM
, COALESCE(DATE_SUB(NEXT_DATE_FROM,INTERVAL 1 SECOND), END_DATETIME) AS DATE_TILL
FROM CTE_UNDERLAPS
WHERE DATE_ADD(DATE_TILL,INTERVAL 1 SECOND) < COALESCE(NEXT_DATE_FROM, END_DATETIME)
ORDER BY LOCATION_ID, DATE_FROM, DATE_TILL
LOCATION_ID
DATE_FROM
DATE_TILL
193
2019-01-01 00:00:00
2019-01-31 23:59:59
193
2020-01-01 00:00:00
2020-01-31 23:59:59
193
2023-01-01 00:00:00
9999-12-31 23:59:59
204
2019-01-01 00:00:00
2019-12-31 23:59:59
204
2022-01-01 00:00:00
9999-12-31 23:59:59
Demo on db<>fiddle here

Search between two dates with specific time with each date

I have two dates. 2019-01-01(fromDate) and 2019-01-10(toDate). And now I want to search only the 13:00 to 16:00 time of each date. May I ask if is it possible using query only? Any answer is much appreciated
SELECT *
FROM table
WHERE fromDate >= 2019-01-01 AND toDate <= 2019-01-10
You can try to use STR_TO_DATE function with the format and HOUR function.
SELECT *
FROM table
WHERE
fromDate >= STR_TO_DATE('2019-01-01', '%Y-%m-%d')
AND
toDate <= STR_TO_DATE('2019-01-10', '%Y-%m-%d')
AND
(HOUR(fromDate) BETWEEN 13 AND 16 OR HOUR(toDate) BETWEEN 13 AND 16)
Use separate conditions on the date and on the time:
SELECT *
FROM table
WHERE fromDate >= '2019-01-01' AND
toDate < '2019-01-11' and
time(fromdate) between '13:00:00' and '16:00:00' and
time(todate) between '13:00:00' and '16:00:00;
Or, if you don't want 16:00:00 exactly, you can use hour():
SELECT *
FROM table
WHERE fromDate >= '2019-01-01' AND
toDate < '2019-01-11' and
hour(fromdate) in (13, 14, 15) and
hour(todate) in (13, 14, 15)

MYSQL - Update row when the date more than 1 year

I am had a query could able to update the row if DateTimeAdded is 1 year or more. But i find out that it wouldn't work in leap year. Anyone have better suggestion?
CREATE EVENT UpdateProduct
ON SCHEDULE
EVERY 1 DAY
DO
update `product` set Label = "ClearStock" where datediff(now(),
DateTimeAdded) >= 365
To identify rows that have DateTimeAdded value over a year old, you could do something like this:
... WHERE DateTimeAdded < NOW() + INTERVAL -1 YEAR
FOLLOWUP
Demonstration:
SELECT NOW() + INTERVAL 0 HOUR AS `now`
, DATE(NOW()) + INTERVAL -1 YEAR AS `year_ago`
, t.DateTimeAdded
, t.DateTimeAdded < DATE(NOW()) + INTERVAL -1 YEAR AS `compare`
FROM ( SELECT '2015-01-24 11:00:00' AS `DateTimeAdded`
UNION ALL
SELECT '2015-01-25 13:00:00'
UNION ALL
SELECT '2015-01-26 14:00:00'
) t
returns:
NOW year_ago DateTimeAdded compare
------------------- ---------- ------------------- -------
2016-01-25 22:11:56 2015-01-25 2015-01-24 11:00:00 1
2016-01-25 22:11:56 2015-01-25 2015-01-25 13:00:00 0
2016-01-25 22:11:56 2015-01-26 2015-01-26 14:00:00 0

How can i get two row from 1 in duration mysql?

I have rows like:
id, start_date, end_date
0, 2000-01-01 20:00:00, 2000-01-01 21:00:00
1, 2000-01-01 23:00:00, 2000-01-02 04:00:00
And I need get reporting result like:
date | time_online
2000-01-01 | 02:00:00
2000-01-02 | 04:00:00
My solution was wrong cos i only start_date count.
SELECT DATE_FORMAT(start_date, '%Y-%m-%d') as date,
SUM(CASE WHEN EXTRACT(DAY FROM start_date) <> EXTRACT(DAY FROM end_date)
THEN
TIMESTAMPDIFF(SECOND, start_date, DATE_FORMAT(start_date + INTERVAL 1 DAY, '%Y-%m-%d'))
ELSE
TIMESTAMPDIFF(SECOND, start_date, end_date) END) time_online
FROM online
GROUP BY date
Result:
date | time_online
2000-01-01 | 02:00:00
Can someone help me?
What you need is a (virtual) reference table with a 24 hour timespan for each date in the online table.
You can use the table itself to do that:
SELECT
DATE(start_date) + INTERVAL 0 HOUR ref_start,
DATE(start_date) + INTERVAL 24 HOUR ref_end
FROM
online
WHERE
end_date IS NOT NULL
UNION DISTINCT
SELECT
DATE(end_date) + INTERVAL 0 HOUR ref_start,
DATE(end_date) + INTERVAL 24 HOUR ref_end
FROM
online
WHERE
end_date IS NOT NULL
The + INTERVAL 0 HOUR is not really neccesary, I added that for clarity, the same goes for the DISTINCT keyword.
If you put this in a subquery then you can get with a (kind of) self-join the records with overlaps, and the calculate the difference depending on the the values:
SELECT
DATE(r.ref_start) ref_date,
SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND,
CASE WHEN d.start_date >= r.ref_start
THEN d.start_date
ELSE r.ref_start
END,
CASE WHEN d.end_date <= r.ref_end
THEN d.end_date
ELSE r.ref_end
END))) time_online
FROM
(
SELECT
DATE(start_date) + INTERVAL 0 HOUR ref_start,
DATE(start_date) + INTERVAL 24 HOUR ref_end
FROM
online
WHERE
end_date IS NOT NULL
UNION DISTINCT
SELECT
DATE(end_date) + INTERVAL 0 HOUR ref_start,
DATE(end_date) + INTERVAL 24 HOUR ref_end
FROM
online
WHERE
end_date IS NOT NULL
) r
JOIN
online d
ON d.end_date > r.ref_start
AND d.start_date < r.ref_end
GROUP BY ref_date

mysql - How to get data by date range given only month and year

Below is my mysql table:
--------------------------
ID Date_From Date_To
--------------------------
1 2011-02-01 2011-02-28
2 2012-09-01 2012-09-30
3 2012-10-01 2012-10-30
4 2012-11-01 2012-11-30
5 2012-12-01 2012-12-30
6 2013-01-01 2013-01-30
7 2014-03-01 2014-03-31
I have this mysql statement:
SELECT *
FROM TIME_PERIOD
WHERE
(YEAR(DATE_FROM) >= '2012' AND MONTH(DATE_FROM) >= '10')
AND (YEAR(DATE_TO) <= '2013' AND MONTH(DATE_TO) <= '12');
which returns only the records with ID 3, 4, and 5. What Im expecting to return are records with ID 3, 4, 5, and 6.
Please help.
You need to use query like this:
SELECT * FROM TIME_PERIOD WHERE
(YEAR(DATE_FROM) >= '2013' OR (YEAR(DATE_FROM) >= '2012' AND
MONTH(DATE_FROM) >= '10')) AND
(YEAR(DATE_TO) <= '2013' AND MONTH(DATE_TO) <= '12');
Month seems to be 01 in record 6. It wont return that because MONTH(DATE_FROM) >= '10'
In id 6 the from date is 2013-01-01 and it fails in 2013-01-01 as the month is 01 which is less than 10. As you have mentioned all and condition so any false will not include that record.
You can create a separate column as year_month like YYYYMM and create two triggers to automatically update the column ON INSERT and ON UPDATE if required.
Then the query would be as simple as
WHERE year_month >= 201210 and year_month <= 201312
You can use this command to get your result ...
SELECT * FROM `TIME_PERIOD` WHERE `DATE_FROM` >= '2012-10-01' AND `DATE_TO` <= '2013-01-30'