2010-09-01 155 views
1

考虑下面的表和行列:转换行允许重复

上市A.

ID, name, event, type 
1, 'John Doe', '2010-09-01 15:00:00.000', 'input' 
1, 'John Doe', '2010-09-03 11:00:00.000', 'input' 
1, 'John Doe', '2010-09-04 17:00:00.000', 'input' 
1, 'John Doe', '2010-09-02 15:00:00.000', 'output' 
1, 'John Doe', '2010-09-03 16:00:00.000', 'output' 
1, 'John Doe', '2010-09-06 17:00:00.000', 'output' 

我想要的是将行转换成列,所以我可以有两个不同的列,输入事件并输出事件。像:

上市B.

ID, name, input event, output event 
1, 'John Doe', '2010-09-01 15:00:00.000', '2010-09-02 15:00:00.000' 
1, 'John Doe', '2010-09-03 11:00:00.000', '2010-09-03 16:00:00.000' 
1, 'John Doe', '2010-09-04 17:00:00.000', '2010-09-06 17:00:00.000' 

我能得到类似如下:

清单C.

ID, name, input event, output event 
1, 'John Doe', '2010-09-01 15:00:00.000', null 
1, 'John Doe', '2010-09-03 11:00:00.000', null 
1, 'John Doe', '2010-09-04 17:00:00.000', null 
1, 'John Doe', null, '2010-09-02 15:00:00.000' 
1, 'John Doe', null, '2010-09-03 16:00:00.000' 
1, 'John Doe', null, '2010-09-06 17:00:00.000' 

,但问题是如何平行,因为重复元组的ID-name是相关的。要转换行到列我通常这样的代码的东西:

select ID, name, max(case when type = 'input' then event else null end) as 'input event', max(case when type = 'output' then event else null end) as 'output event' from events group by ID, name 

,但当然,本集团将要离开了重复,这就是我不想要什么。

任何想法如何实现与查询?

这将是一个便携式SQL解决方案或postgresql,但任何想法非常感谢,很高兴。

编辑:抱歉,迟到的答案。 AlexRednic和Mark Ba​​nnister的解决方案都能达到我想要的效果。我终于选择了第二个,因为它对我来说更加清晰。谢谢你的回答!

+0

您还没有表示如何将输入和输出事件联系起来。 ID和名称本身不会这样做,因为每个类型有三个相同的ID和名称的事件。从提供的数据中,ID,姓名和时间的组合可以唯一地识别每种类型的单个事件,但是单凭这一点对于无数代表性数据集是可靠的,还是可能存在多个输出事件天)为一个单一的ID,姓名和时间? – 2010-09-01 12:47:43

+0

对于任何输入事件,只能有一个输出事件,输出事件的日期总是比输入事件更早。另外,输入事件之后总会有输出事件。不能有两个连续的输入事件。我的错,所提供的数据集不符合这一点。我会纠正它。 – Gothmog 2010-09-01 17:36:37

+0

更清晰,谢谢! – 2010-09-02 09:56:41

回答

2

尝试以下操作:

select ID, name, event as 'input event', 
     (select min(o.event) 
     from events o 
     where o.type = 'output' and 
       i.ID = o.ID and 
       i.name = o.name and 
       i.event < o.event) as 'output event' 
from events i 
where i.type = 'input' 
group by ID, name, event 
0

我从一开始就写着:

create table #a(
ID int, 
name varchar(30), 
event datetime, 
type varchar(10) 
) 

insert #a 
select 
1, 'John Doe', '2010-09-01 15:00:00.000', 'input' 
union select 1, 'John Doe', '2010-09-01 16:00:00.000', 'input' 
union select 1, 'John Doe', '2010-09-01 17:00:00.000', 'input' 
union select 1, 'John Doe', '2010-09-02 15:00:00.000', 'output' 
union select 1, 'John Doe', '2010-09-02 16:00:00.000', 'output' 
union select 1, 'John Doe', '2010-09-02 17:00:00.000', 'output' 

- 这里是解决方案SQL

select 
    ID, 
    name, 
    case when type = 'input' then event else null end "input event", 
    case when type = 'output' then event else null end "output event" 
from #a 
+0

我走到了这一步,但这不是我想要的。我想要获得的结果只有三行。列表B. – Gothmog 2010-09-01 17:28:33

+0

好的我看到了,但列表B没有有效的groupin逻辑。你能否说通常“把相同的日期排成一行”?如果你说是,它的正确,我会正确的SQL? – 2010-09-02 07:16:22

1
select t1.id,t1.name,t1.event,t2.event from test t1 
    inner join test t2 on t1.event <= t2.event 
     and t1.type = 'input' 
     and t2.type = 'output' 
        and t1.id = t2.id 
        and t1.name = t2.name 

是你需要以某种方式输入链接的事/输出会话。在这个查询中,我通过使用时间戳事件列来完成它。如果这不是你想要的,你能提供更多的信息吗?

更新:现在,到后处理了一下,你可以做

with a as 
(
select t1.id,t1.name,t1.event as in_event,t2.event as out_event from test t1 
    inner join test t2 on t1.event <= t2.event 
        and t1.type = 'input' 
        and t2.type = 'output' 
        and t1.id = t2.id 
        and t1.name = t2.name 
) 
select id,name,in_event,min(out_event) 
     from a 
group by id,name,in_event 
+0

这将返回0行,因为输入事件与输出事件在不同的日期(但同时) - 输入发生在第一个输出上,输出发生在第二个输出上。如果输入/输出的日期与示例中所表示的日期相同,则 – 2010-09-01 12:42:41

+0

工作。这就是我所说的,我需要更多关于这两个事件如何链接的信息。它是event.input <= event.output?来自Gothmog的响应中的 – AlexRednic 2010-09-02 10:28:50

+0

,event.input 2010-09-02 10:47:00