【问题标题】:Combine 2 rows into 1 row (Start and End times)将 2 行合并为 1 行(开始和结束时间)
【发布时间】:2020-04-08 17:29:32
【问题描述】:

我不知道如何措辞,但我在单独的行中有 StartEnd 时间,我想将它们合并成一行。在这个示例数据中,它基本上是跟踪/记录项目时间:

Project  Type    Time
A        Start   1:00
A        End     1:10
B        Start   2:00
B        End     2:10
B        Start   2:30
B        End     2:45
C        End     3:00
D        Start   3:10
D        End     3:20

我正在寻找的是这样的:

Project  Start    End
A        1:00     1:10
B        2:00     2:10
B        2:30     2:45
C        NULL     1:10
D        3:10     3:20

奇怪的两部分是:

  • 同一项目可能有多个开始/结束时间对(例如 如上面的项目B),可能背靠背或在同一天分开
  • 我可能缺少一些开始或结束 次。

谁能指出我正确的方向?我在 Stackoverflow 上找不到任何具有相同要求的内容。

【问题讨论】:

  • 如果你有 START START END END 你想要什么?
  • 我会采用第一个 START 并将其与第一个后续 END 配对。以下 END 将有一个 NULL 配对的 START 时间
  • ...第二个 START 将与 NULL END 时间配对

标签: sql sql-server group-by window-functions gaps-and-islands


【解决方案1】:

这是某种差距和孤岛问题。

我会用lag() 和一个窗口sum() 来解决这个问题。每次连续记录类型不是'Start' 后跟'End' 时,都会启动一个新组。

select 
    project, 
    min(case when type = 'Start' then time end) Start,
    max(case when type = 'End' then time end) [End]
from (
    select
        t.*,
        sum(case when type = 'End' and lag_type = 'Start' then 0 else 1 end) 
            over(partition by project order by time) grp
    from (
        select
            t.*,
            lag(type) over(partition by project order by time) lag_type
        from mytable t
    ) t
) t
group by project, grp
order by project, grp

Demo on DB Fiddle

项目 |开始 |结尾 :-------- | :---- | :--- 一个 | 1:00 | 1:10 乙| 2:00 | 2:10 乙| 2:30 | 2:45 C | | 3:00 D | 3:10 | 3:20

【讨论】:

  • @Gordon Linoff 确实提出了一个很好的问题。按时间顺序,如果在第一个 END 之前有多个 START 时间,则第一个 START 应与第一个 END 配对,中间的任何其他 START 时间应与 NULL END 时间配对。我在这里与 DB Fiddle 一起工作,但不知道如何处理 Lag:[link] dbfiddle.uk/… [/link] 有没有办法调整这个?
【解决方案2】:

ROW_NUMBER的帮助下,我们可以在这里尝试使用旋转逻辑:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Project, Type ORDER BY Time) rn
    FROM yourTable
)

SELECT
    Project,
    MAX(CASE WHEN Type = 'Start' THEN Time END) AS Start,
    MAX(CASE WHEN Type = 'End'   THEN Time END) AS [End]
FROM cte
GROUP BY
    Project,
    rn
ORDER BY
    Project,
    rn;

Demo

【讨论】:

  • 这对于一个悬空的“END”非常有效,但是如果我在悬空的“END”时间之后添加另一个正确配对的“START”和“END”,它就不能正确配对。我在这里的项目 B 部分对其进行了测试:[link] dbfiddle.uk/… [/link]。 B 2:30 START 应该在第 3 B 行,而不是第 2 B 行。有没有办法调整这条 SQL 语句?
  • @Error500 我根据我看到的数据来回答,而不是根据我没有看到的数据。在这种情况下,您应该使用解释所有边缘情况的数据提出更好的问题。我的答案适用于您显示的数据。
  • 抱歉,我正在测试其他可能会被我弄丢的潜在数据。不过,我非常感谢您的回复
  • @GMB 的答案与您可能有许多丢失的数据点所需要的一致。实际上,在这种情况下,您的问题是标准的差距和孤岛问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-14
  • 1970-01-01
  • 2014-05-31
  • 2019-03-09
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多