MySQL根据匹配的日期将多行合并为一行

时间:2019-12-03 23:39:53

标签: mysql sql concat gaps-and-islands

我的数据示例:

+----+------------+------------+-----------+--------------+--+
| ID | startdate  |  enddate   |  status   | lengthofstay |  |
+----+------------+------------+-----------+--------------+--+
|  1 | 2018-02-15 | 2018-02-16 | transfer  |            1 |  |
|  1 | 2018-02-16 | 2018-02-22 | discharge |            6 |  |
|  2 | 2018-03-05 | 2018-03-08 | discharge |            3 |  |
|  1 | 2018-11-01 | 2018-11-03 | transfer  |            2 |  |
|  1 | 2018-11-03 | 2018-11-20 | transfer  |           17 |  |
|  1 | 2018-11-20 | 2018-11-21 | discharge |            1 |  |
|  2 | 2019-05-15 | 2019-05-20 | discharge |            5 |  |
+----+------------+------------+-----------+--------------+--+

我要解决两个问题。 首先,我想根据匹配的开始日期和结束日期将具有匹配ID的行合并为一行,同时还要获取lengthofstay的总和(开始日期和结束日期之间的datediff)。 第二个问题是,我有重复的ID,我希望将其作为以后的观察结果再次保存在系统中。

这是我理想的输出:

+----+------------+------------+-----------+--------------+
| ID | startdate  |  enddate   |  status   | lengthofstay |
+----+------------+------------+-----------+--------------+
|  1 | 2018-02-15 | 2018-02-22 | discharge |            7 |
|  2 | 2018-03-05 | 2018-03-08 | discharge |            3 |
|  1 | 2018-11-01 | 2018-11-21 | discharge |           20 |
|  2 | 2019-05-15 | 2019-05-20 | discharge |            5 |
+----+------------+------------+-----------+--------------+

我在MySQL方面没有太多的经验,我不确定是否可以通过汇总使用join,concat或group by。我知道在单独的场合重复输入ID是另一个问题,因此我考虑根据每个唯一ID的起始日期与最后一个终止日期相距多远(例如3天的间隔)来涉及另一个标识符,但是我没有知道怎么做。

我发现了类似的问题here,但没有答案。

我非常感谢您的见解!

1 个答案:

答案 0 :(得分:2)

这是一个孤岛问题。这是使用MySQL 8.0中可用的窗口函数解决此问题的一种方法:

select
    id,
    min(startdate) startdate,
    max(enddate) enddate,
    last_status status,
    sum(lengthofstay) lengthofstay
from (
    select
        t.*,
        last_value(status) over(partition by id, rn1 - rn2) last_status
    from (
        select
            t.*,
            row_number() over(order by startdate) rn1,
            row_number() over(partition by id order by startdate) rn2
        from mytable t
    ) t
) t
group by
    id,
    last_status,
    rn1 - rn2
order by min(startdate)

查询通过对两个不同分区上的记录进行排序来工作;等级之间的差异为您提供了所属的组。然后,last_value()可用于检索每个组中的最后状态。最后一步是聚合。

Demo on DB Fiddle

id | startdate  | enddate    | status    | lengthofstay
-: | :--------- | :--------- | :-------- | -----------:
 1 | 2018-02-15 | 2018-02-22 | discharge |            7
 2 | 2018-03-05 | 2018-03-08 | discharge |            3
 1 | 2018-11-01 | 2018-11-21 | discharge |           20
 2 | 2019-05-15 | 2019-05-20 | discharge |            5