views:

81

answers:

3

Consider the following table and rows:

Listing 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'

What I want is to convert rows into columns, so I can have two different columns, input event and output event. Like:

Listing 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'

I was able to get something like following:

Listing 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'

, but the problem is how to flat the rows, since the duplicate tuples ID-name ARE relevant. To convert rows into columns I usually code something like this:

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

, but of course, the GROUP BY is going to leave out the duplicates, and that's what I don't want.

Any ideas how to achieve that with a query?

It would be nice to have a portable sql solution or for postgresql, but any idea is much appreciated.

EDIT: sorry for late answer. Both solutions from AlexRednic and Mark Bannister accomplish what I wanted. I finally opted for the second one, since it looks clearer to me. Thanks all for your answers!

A: 

I'm writing from the beginning:

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'

-- here is the solution 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
Burçin Yazıcı
I got to this step, but this is not what I want. The result I want to obtain is only three rows. The listing B.
Gothmog
ok I see but listing B does not have valid groupin logic then. Can you say that as a rule "put the same dates as one row"? If you say yes, its possiple and I'll right the sql?
Burçin Yazıcı
+1  A: 

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

The thing is you need somehow to link the input/output sessions. In this query I did it by using the timestamp event column. Could you provide more information if this isn't what you wanted?

Update: now, to post-process a bit you could do

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

AlexRednic
This would return 0 rows, as the input event is on a different date (but at the same time) to the output event - inputs happen on the first, outputs on the second.
Mark Bannister
worked if the dates of input/output are the same as expressed in the example. That's what I said, I need more info on how the two events are linked. Is it event.input <= event.output ?
AlexRednic
@Alex: from Gothmog's response, event.input < event.output.
Mark Bannister
yeah... for some reason I doesn't show up.... I still have to get along with the code formatting
AlexRednic
+2  A: 

Try the following:

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
Mark Bannister