如何将 SQL 中的行合并为一行?
How to combine rows into one row in SQL?
我遇到了复杂需求的问题,我希望能得到一些帮助来解决这个问题。我的 SQL 知识很基础,我不知道如何解决这个问题。目前,我有一个 Events
table 结构如下:
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
换句话说,我有两个新列:Arrival
和 Departure
。然后对于 table 中的每个人,按时间顺序应用以下逻辑:
- 如果
Event Type
是 Arrival
,它应该映射到 Arrival
列中具有 Time
值的新行。
- 如果
Event Type
是 Departure
,检查上一行是否也是 Departure
。如果是这样,它应该映射到 Departure
列中具有 Time
值的新行,并且 Arrival
为空。如果不是,只需将 Time
值转移到上一行的 Departure
列中。
最好是可以通过 SQL 查询来完成,但函数也可以。我正在使用 MS SQL 服务器。谢谢!
您可以通过多种方式执行此操作。一种方法是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
代替。
如果您的数据始终包含正确数量的到达行,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
这将为所有行分配一个行号,如果该行是出发,而前一行是到达,它将从行号中减去一个 -> 这些行将具有相同的编号.然后使用此数字对数据进行分组,因此所有孤立行将单独显示。
我遇到了复杂需求的问题,我希望能得到一些帮助来解决这个问题。我的 SQL 知识很基础,我不知道如何解决这个问题。目前,我有一个 Events
table 结构如下:
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
换句话说,我有两个新列:Arrival
和 Departure
。然后对于 table 中的每个人,按时间顺序应用以下逻辑:
- 如果
Event Type
是Arrival
,它应该映射到Arrival
列中具有Time
值的新行。 - 如果
Event Type
是Departure
,检查上一行是否也是Departure
。如果是这样,它应该映射到Departure
列中具有Time
值的新行,并且Arrival
为空。如果不是,只需将Time
值转移到上一行的Departure
列中。
最好是可以通过 SQL 查询来完成,但函数也可以。我正在使用 MS SQL 服务器。谢谢!
您可以通过多种方式执行此操作。一种方法是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
代替。
如果您的数据始终包含正确数量的到达行,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
这将为所有行分配一个行号,如果该行是出发,而前一行是到达,它将从行号中减去一个 -> 这些行将具有相同的编号.然后使用此数字对数据进行分组,因此所有孤立行将单独显示。