Example tables are below,
CREATE TABLE TIMEOFF_INFO (
TIMEOFF_ID INT PRIMARY KEY,
TIMEOFF_BEGIN DATE NOT NULL,
TIMEOFF_END DATE NOT NULL
)
and example rows below,
------------ --------------- -------------
| timeoff_id | timeoff_begin | timeoff_end |
------------ --------------- -------------
| 1 | 2021-10-01 | 2021-10-02 |
------------ --------------- -------------
| 2 | 2021-11-15 | 2021-11-15 |
------------ --------------- -------------
| 3 | 2021-12-18 | 2021-12-20 |
------------ --------------- -------------
What I want to get is convert table above to below so that I can join using each date in range.
2021-10-01 (id: 1's begin date)
2021-10-02 (id: 1's end date)
2021-11-15 (id: 2's begin and end date)
2021-12-18 (id: 3's begin date)
2021-12-19
2021-12-20 (id: 3's end date)
Is there any way to extend date range in single row to series of Date row?
CodePudding user response:
You could use a union all on the same table
select id, timeoff_begin timeoff, concat(id, ' begin date') msg
from TIMEOFF_INFO
union all
select id, timeoff_end, concat(id, ' end date')
from TIMEOFF_INFO
order by id, timeoff
CodePudding user response:
WITH RECURSIVE
daterange AS ( SELECT MIN(TIMEOFF_BEGIN) dStart, MAX(TIMEOFF_END) dEnd
FROM TIMEOFF_INFO ),
calendar AS ( SELECT dStart `date`
FROM daterange
UNION ALL
SELECT `date` INTERVAL 1 DAY
FROM calendar
WHERE `date` < ( SELECT dEnd FROM daterange ) )
SELECT calendar.`date`
FROM calendar
WHERE EXISTS ( SELECT NULL
FROM TIMEOFF_INFO
WHERE calendar.`date` BETWEEN TIMEOFF_INFO.TIMEOFF_BEGIN AND TIMEOFF_INFO.TIMEOFF_END )
MariaDB 10.2 or MySQL 8 needed.
CodePudding user response:
Much the same as @akina but less sophisticated. Here a cte is used simply to identify those where the date difference is > 1 then join to a dates table and unioned. the begin , intermediate and end dates are identified by a flag which is used to order by. This could be done without a cte but a cte does help clarify(i think), Note I have amended the sample data slightly
drop table if exists t;
create table t
(timeoff_id int, timeoff_begin date, timeoff_end date);
insert into t values
( 1 , '2020-10-01' , '2020-10-05'),
( 2 , '2020-11-15' , '2020-11-15'),
( 3 , '2020-12-18' , '2020-12-21');
with cte as
(select 2 as beg,timeoff_id , timeoff_begin, timeoff_end ,datediff(timeoff_end, timeoff_begin) diff
from t
where datediff(timeoff_end, timeoff_begin) > 1)
select cte.beg,cte.timeoff_id,dates.dte
from cte
join dates where dates.dte > cte.timeoff_begin and dates.dte <= date_add(cte.timeoff_begin, interval cte.diff -1 day)
union all
(select 1 as beg,timeoff_id , timeoff_begin dt from t
union all
select 3 ,timeoff_id , timeoff_end from t
)
order by timeoff_id, beg,dte;
----- ------------ ------------
| beg | timeoff_id | dte |
----- ------------ ------------
| 1 | 1 | 2020-10-01 |
| 2 | 1 | 2020-10-02 |
| 2 | 1 | 2020-10-03 |
| 2 | 1 | 2020-10-04 |
| 3 | 1 | 2020-10-05 |
| 1 | 2 | 2020-11-15 |
| 3 | 2 | 2020-11-15 |
| 1 | 3 | 2020-12-18 |
| 2 | 3 | 2020-12-19 |
| 2 | 3 | 2020-12-20 |
| 3 | 3 | 2020-12-21 |
----- ------------ ------------