Py学习  »  DATABASE

MySQL或MariaDB将单行中的日期范围扩展为多个系列行

Gipyo.Choi • 3 年前 • 1118 次点击  

示例表如下:,

CREATE TABLE TIMEOFF_INFO (
  TIMEOFF_ID INT PRIMARY KEY,
  TIMEOFF_BEGIN DATE NOT NULL,
  TIMEOFF_END DATE NOT NULL
)

以及下面的示例行,

+------------+---------------+-------------+
| 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  |
+------------+---------------+-------------+

我想得到的是将上表转换为下表,这样我就可以使用范围内的每个日期加入。

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)

有没有办法将单行中的日期范围扩展到一系列日期行?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/128961
 
1118 次点击  
文章 [ 3 ]  |  最新文章 3 年前
scaisEdge
Reply   •   1 楼
scaisEdge    3 年前

你可以在同一张桌子上使用一个工会

    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
P.Salmon
Reply   •   2 楼
P.Salmon    3 年前

与@akina差不多,但不那么复杂。此处,cte仅用于识别日期差异大于;1然后加入日期表并联合。开始日期、中间日期和结束日期由一个用于订购的标志标识。 这可以在没有cte的情况下完成,但cte确实有助于澄清(我认为), 注:我对样本数据进行了轻微修改

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 |
+-----+------------+------------+
Akina
Reply   •   3 楼
Akina    3 年前
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+或MySQL 8+。