如何在SQL中将行组合成一行?

时间:2016-03-24 19:27:55

标签: sql sql-server tsql sql-view

我遇到了复杂要求的问题,我希望能在解决这个问题上得到一些帮助。我的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,则应将其映射到Time列中Arrival值的新行。
  • 如果Event TypeDeparture,请检查上一行是否也是Departure。如果是,则应将其映射到Time列中Departure值为Arrival的新行,Time为空。如果没有,只需将Departure值转移到上一行的*{margin:0;} #container-main{ height: 100%; width: 100%; overflow: hidden; } #container-sub{ width: 100%; height: 99%; overflow: auto; padding-right: 15px; } html, body{ height: 99%; overflow:hidden; }列即可。

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

如果您的数据始终具有正确数量的到达行,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

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