根据日期重叠转换表格

问题描述 投票:0回答:1

问题陈述

您好,我是一名 SQL 初学者。我可以访问数据库进行研究,有一个感兴趣的表,结构如下:

id
date
use
item
1 2023-02-01 90 A
1 2023-03-01 10 B
1 2023-03-15 15 C
2 2023-02-05 10 B
2 2023-02-13 30 A

这是由人员

item
完成的
date
获取
id
的表格。我想根据每个人员
date
的重叠来转换此表
id
,但不太确定如何实现这一点。

所需输出

我想结果表如下:

id
start
end
item
1 1 29 A
1 30 39 A、B
1 40 43 A
1 44 58 A、C
1 59 90 A
2 1 8 B
2 9 10 A、B
2 11 38 A

粗略的想法

我的想法是:

  1. 我想使用

    date
    作为每个人员的起始索引来转换表格
    id

  2. 这样,我们就可以将变换后的

    date
    转换为
    use
    ,从而获得相对的使用结束日期为
    start
    +
    use
    - 1

    id
    start
    use
    end
    item
    1 1 90 90 A
    1 30 10 39 B
    1 44 15 58 C
    2 1 10 10 B
    2 9 30 38 A
  3. 从视觉上看,每个人员的物品获取过程将是:

    人员1:

                                                  +--------------C (15)  
                                   +---------B (10)  
    +------------------------------------------------------------------------------------------A (90)  
    +------------------------------+--------------+-------------------------------------------->  
    1                              30             44                                         90  
    

    人员2:

            +--------------------------------A (30)  
    +---------B (10)  
    +-------+-------------------------------->  
    1       9                              40  
    
  4. 最后,我可以评估并发项目获取如下:

    id
    start
    end
    item
    1 1 29 A
    1 30 39 A、B
    1 40 43 A
    1 44 58 A、C
    1 59 90 A
    2 1 8 B
    2 9 10 A、B
    2 11 38 A

我发现了什么

我找到了一些与这个问题相关的主题,包括:

我尝试了什么

-- Create a dummy table
CREATE TABLE tbl (
  id int,
  start_date date,
  day_of_use int,
  item varchar(8)
)
;

-- Populating table with sample data
INSERT INTO tbl VALUES (1, "2023-02-01", 90, "A");
INSERT INTO tbl VALUES (1, "2023-03-02", 10, "B");
INSERT INTO tbl VALUES (1, "2023-03-15", 15, "C");
INSERT INTO tbl VALUES (2, "2023-02-05", 10, "B");
INSERT INTO tbl VALUES (2, "2023-02-13", 30, "A");

-- Querying the overlap
SELECT
  a.id,
  DATEDIFF(a.start_date, b.init) + 1 AS start,
  day_of_use,
  DATEDIFF(a.start_date, b.init) + day_of_use AS end,
  item
FROM
  tbl AS a
  LEFT JOIN
  (
    SELECT id, MIN(start_date) AS init
    FROM tbl
    GROUP BY id
    ORDER BY id
  ) AS b ON a.id = b.id
;

不过,我不知道如何从这里开始。任何想法将不胜感激,提前致谢。 SQL小提琴:https://www.db-fiddle.com/f/eB1GnZTuuH5P71kr4pWqHu/2

sql mysql date overlap gaps-and-islands
1个回答
0
投票

如果您使用的是 MySQL 8.0,您可以尝试:

  • 用递归 cte 展开你的值
  • 将您的问题视为间隙和岛屿问题
  • 聚合以收集您的价值观

为了解决间隙和孤岛问题,您可能需要使用连续记录中项目更改量的运行总和来重新创建分区。

WITH RECURSIVE cte AS (
    SELECT id, start_date AS date_, day_of_use, item
    FROM tbl
  
    UNION ALL 
  
    SELECT id, DATE_ADD(date_, INTERVAL 1 DAY), day_of_use-1, item  
    FROM cte
    WHERE day_of_use > 0
), cte2 AS (
    SELECT id, 
           DENSE_RANK() OVER(PARTITION BY id ORDER BY date_) AS rn, 
           item
    FROM cte
), cte3 AS (
    SELECT id, 
           rn,
           GROUP_CONCAT(item ORDER BY item) AS items,
           LAG(GROUP_CONCAT(item ORDER BY item)) OVER(PARTITION BY id) AS prev_items
    FROM cte2
    GROUP BY id, rn
), cte4 AS (
    SELECT id, rn, items,
           COUNT(CASE WHEN prev_items != items THEN 1 END) OVER(PARTITION BY id ORDER BY rn) AS parts
    FROM cte3 
)
SELECT id, MIN(rn) AS start_, MAX(rn) AS end_, items 
FROM cte4
GROUP BY id, items, parts

输出”:

id 项目 开始_ 完_
1 A 1 29
1 A、B 30 40
1 A 41 42
1 A、C 43 58
1 A 59 91
2 B 1 8
2 A、B 9 11
2 A 12 39

查看演示这里

请注意,2023 年 2 月没有 29 天。

© www.soinside.com 2019 - 2024. All rights reserved.