【问题标题】:How to combine rows into one row in SQL?如何在 SQL 中将行合并为一行?
【发布时间】:2016-07-12 12:49:54
【问题描述】:

我遇到了复杂要求的问题,我希望能得到一些帮助来解决这个问题。我的 SQL 知识很基础,我不知道如何解决这个问题。目前,我有一个Events 表,其结构如下:

ID     | Name  | Time                    | Event Type
----------------------------------------------------------
133000 | Elise | 2016-02-17 06:39:42.000 | Arrival
133000 | Elise | 2016-02-18 06:20:22.000 | Arrival
133000 | Elise | 2016-02-18 20:43:46.000 | Departure
133020 | Elise | 2016-02-19 06:29:46.000 | Arrival
133445 | Peter | 2016-02-01 20:09:00.000 | Departure
133445 | Peter | 2016-02-02 06:32:02.000 | Arrival
133445 | Peter | 2016-02-02 17:03:04.000 | Departure
133445 | Peter | 2016-02-02 19:44:06.000 | Arrival
133445 | Peter | 2016-02-02 19:56:56.000 | Departure

现在,我想以某种方式查询这些数据,使其结构如下:

ID     | Name  | Arrival                 | Departure
----------------------------------------------------------
133000 | Elise | 2016-02-17 06:39:42.000 | NULL
133000 | Elise | 2016-02-18 06:20:22.000 | 2016-02-18 20:43:46.000
133000 | Elise | 2016-02-19 06:29:46.000 | NULL
133445 | Peter | NULL                    | 2016-02-01 20:09:00.000
133445 | Peter | 2016-02-02 06:32:02.000 | 2016-02-02 17:03:04.000
133445 | Peter | 2016-02-02 19:44:06.000 | 2016-02-02 19:56:56.000

换句话说,我有两个新列:ArrivalDeparture。然后对于表中的每个人,按时间顺序应用以下逻辑:

  • 如果Event TypeArrival,则应将其映射到Arrival 列中具有Time 值的新行。
  • 如果Event TypeDeparture,检查前一行是否也是Departure。如果是这样,则应将其映射到Departure 列中具有Time 值的新行,并且Arrival 为空。如果没有,只需将Time 值转移到上一行的Departure 列。

最好可以通过 SQL 查询来完成,但函数也可以。我正在使用 MS SQL Server。谢谢!

【问题讨论】:

    标签: sql sql-server tsql sql-view


    【解决方案1】:

    您可以通过多种方式做到这一点。一种方法是lead(),但需要小心:

    select id, name, time as Arrival,
           (case when next_eventtype = 'Departure' then next_time end) as Departure
    from (select e.*,
                 lead(time) over (partition by id order by time) as next_time,
                 lead(eventtype) over (partition by id order by time) as next_eventtype,
          from events e
         ) e
    where eventtype = 'Arrival';
    

    lead() 在 SQL Server 2012+ 中可用。在早期版本中,您将改用 apply

    【讨论】:

      【解决方案2】:

      如果您的数据始终具有正确数量的 Arrival 行,Gordon Linoff 的解决方案可能会更好,但如果数据损坏,您可能需要对 row_number 进行更复杂的欺骗,如下所示:

      select 
        Name, 
        max(case when [Event Type] = 'Arrival' then Time end) as Arrival,
        max(case when [Event Type] = 'Departure' then Time end) as Departure
      from (
        select case when [Event Type] = 'Departure' and lag([Event Type]) over (partition by Name order by [Time] asc) = 'Arrival' then RN -1 else RN end as RN2, *
        from (
          select row_number() over (partition by Name order by [Time]) as RN, *
          from yourtable
        ) X
      ) Y
      group by Name, RN2
      order by Name, Arrival, Departure
      

      这将为所有行分配一个行号,如果该行是出发,而前一行是到达,它将从行号中减去一个 -> 这些行将具有相同的编号。然后使用该数字对数据进行分组,因此所有孤立行都将单独显示。

      【讨论】:

      • 我不得不稍微改变一下以使用 apply 而不是 lag,因为我在服务器 '08 上。但这正是我想要的。
      猜你喜欢
      • 2011-09-30
      • 2019-07-14
      • 2023-02-19
      • 2021-08-19
      • 2022-12-18
      • 2019-01-14
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      相关资源
      最近更新 更多