将具有一个DateTime列的行对合并为具有开始日期和结束日期列的单行

时间:2013-12-17 15:42:20

标签: tsql

编辑:关于名称可以有多对不重叠的开头和结尾这一事实需要澄清。因此,合并后的对可以被识别为“运行”。

我猜这是一个重复的问题,但我似乎找不到另一个问题。如果有人可以指出我,那么可以关闭或删除它等等。

我有一个看起来像这样的表:


Id   Name      Action      ActionDate
---- -------   ------      ----------
1    John      Start       01/15/2013
2    Mary      Start       01/17/2013
3    Nancy     Start       01/17/2013
4    John      End         01/18/2013
5    Mary      End         01/18/2013
6    Nancy     End         01/20/2013
7    John      Start       01/19/2013
8    Mary      Start       01/20/2013
9    Nancy     Start       01/25/2013
10   John      End         01/21/2013
11   Mary      End         01/22/2013
12   Nancy     End         01/30/2013

我需要一个使用基于集合的查询看起来像这样的结果集:


Id   Name    Run   StartActionDate    EndActionDate
---- ------- ----  ---------------    -------------
1    John    1     01/15/2013         01/18/2013
2    John    2     01/19/2013         01/21/2013
3    Mary    1     01/17/2013         01/18/2013
4    Mary    2     01/20/2013         01/22/2013
5    Nancy   1     01/17/2013         01/20/2013
6    Nancy   2     01/25/2013         01/30/2013

3 个答案:

答案 0 :(得分:0)

检查出来

select MIN(Id),Name,MIN(case Action when 'Start' then ActionDate End) as StartActionDate,MIN(case Action When 'End' then ActionDate End) as EndActiondate from dbo.Table group by Name

答案 1 :(得分:0)

假设每个名称只有1条带有“开始”的记录和1条带有“结束”的记录,这样的东西应该有效:

SELECT T1.Id, T1.Name, T1.ActionDate AS [StartActionDate], T2.ActionDate AS [EndActionDate]
FROM MyTable T1
INNER JOIN MyTable T2 ON T1.Name = T2.Name
WHERE T1.Action = 'Start' AND T2.Action = 'End'

答案 2 :(得分:0)

虽然如果你有多个id对,你想要返回name并不是很清楚,你应该可以使用像row_number()这样的窗口函数使用操作为每个名称生成唯一序列,然后生成最终结果:

;with cte as
(
  select id, name, action, actiondate,
    row_number() over(partition by name, action
                      order by actiondate) seq
  from yourtable
)
select 
  min(id) id,
  name,
  max(case when action = 'start' then actiondate end) StartActionDate,
  max(case when action = 'end' then actiondate end) EndActionDate
from cte
group by name, seq
order by id;

请参阅SQL Fiddle with Demo

根据您的数据更改,您应该能够使用类似于:

的内容
;with cte as
(
  select id, name, action, actiondate,
    row_number() over(partition by name, action
                      order by actiondate) seq
  from yourtable
)
select 
  row_number() over(order by name) id,
  name,
  seq run,
  max(case when action = 'start' then actiondate end) StartActionDate,
  max(case when action = 'end' then actiondate end) EndActionDate
from cte
group by name, seq
order by id

SQL Fiddle with Demo。这给出了一个结果:

| ID |  NAME | RUN |                STARTACTIONDATE |                  ENDACTIONDATE |
|----|-------|-----|--------------------------------|--------------------------------|
|  1 |  John |   1 | January, 15 2013 00:00:00+0000 | January, 18 2013 00:00:00+0000 |
|  2 |  John |   2 | January, 19 2013 00:00:00+0000 | January, 21 2013 00:00:00+0000 |
|  3 |  Mary |   1 | January, 17 2013 00:00:00+0000 | January, 18 2013 00:00:00+0000 |
|  4 |  Mary |   2 | January, 20 2013 00:00:00+0000 | January, 22 2013 00:00:00+0000 |
|  5 | Nancy |   1 | January, 17 2013 00:00:00+0000 | January, 20 2013 00:00:00+0000 |
|  6 | Nancy |   2 | January, 25 2013 00:00:00+0000 | January, 30 2013 00:00:00+0000 |