join on next row

Started by Sim Zacksalmost 20 years ago12 messagesgeneral
Jump to latest
#1Sim Zacks
sim@compulab.co.il

I am having brain freeze right now and was hoping someone could help me
with a (fairly) simple query.

I need to join on the next row in a similar table with specific criteria.

I have a table with events per employee.
I need to have a query that gives per employee each event and the event
after it if it happened on the same day.

The Events table structure is:

EventID
Employee
EventDate
EventTime
EventType

I want my query resultset to be
Employee,EventDate(1),EventTime(1),EventType(1),EventTime(2),EventType(2)
Where Event(2) is the first event of the employee that took place after
the other event.

Example
EventID Employee EventDate EventTime EventType
1 John 6/15/2006 7:00 A
2 Frank 6/15/2006 7:15 B
3 Frank 6/15/2006 7:17 C
4 John 6/15/2006 7:20 C
5 Frank 6/15/2006 7:25 D
6 John 6/16/2006 7:00 A
7 John 6/16/2006 8:30 R

Expected Results
John, 6/15/2006, 7:00, A, 7:20, C
Frank, 6/15/2006, 7:15, B, 7:17, C
Frank, 6/15/2006, 7:17, C, 7:25, D
John, 6/16/2006, 7:00, A, 8:30, R

To get this result set it would have to be an inner join on employee and
date where the second event time is greater then the first. But I don't
want the all of the records with a greater time, just the first event after.

Thank You
Sim

#2Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: Sim Zacks (#1)
Re: join on next row

It would have been quite easy if done in Oracle's 'lateral view'
feature. But I think it is achievable in standard SQL too; using
subqueries in the select-clause.

Try something like this:

select
Employee, EventDate,
EventTime as e1_time,
EventType as e1_type,
( select
EventTime
from
Events
where Employee = O.Employee
and EventDate = O.EventDate
and EventTime > O.EventTime
limit 1
)as e_time_1,
( select
EventType
from
Events
where Employee = O.Employee
and EventDate = O.EventDate
and EventTime > O.EventTime
limit 1
)
from
Events

Hope it helps...

Regards,
Gurjeet.

Show quoted text

On 6/20/06, Sim Zacks <sim@compulab.co.il> wrote:

I am having brain freeze right now and was hoping someone could help me
with a (fairly) simple query.

I need to join on the next row in a similar table with specific criteria.

I have a table with events per employee.
I need to have a query that gives per employee each event and the event
after it if it happened on the same day.

The Events table structure is:

EventID
Employee
EventDate
EventTime
EventType

I want my query resultset to be
Employee,EventDate(1),EventTime(1),EventType(1),EventTime(2),EventType(2)
Where Event(2) is the first event of the employee that took place after
the other event.

Example
EventID Employee EventDate EventTime EventType
1 John 6/15/2006 7:00 A
2 Frank 6/15/2006 7:15 B
3 Frank 6/15/2006 7:17 C
4 John 6/15/2006 7:20 C
5 Frank 6/15/2006 7:25 D
6 John 6/16/2006 7:00 A
7 John 6/16/2006 8:30 R

Expected Results
John, 6/15/2006, 7:00, A, 7:20, C
Frank, 6/15/2006, 7:15, B, 7:17, C
Frank, 6/15/2006, 7:17, C, 7:25, D
John, 6/16/2006, 7:00, A, 8:30, R

To get this result set it would have to be an inner join on employee and
date where the second event time is greater then the first. But I don't
want the all of the records with a greater time, just the first event after.

Thank You
Sim

---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo@postgresql.org so that your
message can get through to the mailing list cleanly

#3Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: Sim Zacks (#1)
Re: join on next row

I agree about the performance; but it won't be that bad if PG can
unnest these subqueries and convert them into join views!!! In that
case, these views would return just one row (LIMIT 1), and that is the
best a developer can do to help the optimizer make the decision. If
the optimizer knows that a relation in the join is going to return
just one row, it would try to evaluate that relation first, yeilding
better performance in the subsequent join operations.

But I dont think we have a choice; unless, of course, if someday
PG starts supporting Oracle-like 'lateral views', where we can write
have predicates in the where clause of a view which refer the columns
of another relation in the join which this view is a part of!!!

Do let us all know if you find a better solution.

Regards,
Gurjeet.

Show quoted text

On 6/20/06, Sim Zacks <sim@compulab.co.il> wrote:

Thank you for responding.
I was thinking along those lines as well, though that would be an
absolute performance killer.

Gurjeet Singh wrote:

It would have been quite easy if done in Oracle's 'lateral view'
feature. But I think it is achievable in standard SQL too; using
subqueries in the select-clause.

Try something like this:

select
Employee, EventDate,
EventTime as e1_time,
EventType as e1_type,
( select
EventTime
from
Events
where Employee = O.Employee
and EventDate = O.EventDate
and EventTime > O.EventTime
limit 1
)as e_time_1,
( select
EventType
from
Events
where Employee = O.Employee
and EventDate = O.EventDate
and EventTime > O.EventTime
limit 1
)
from
Events

Hope it helps...

Regards,
Gurjeet.

On 6/20/06, Sim Zacks <sim@compulab.co.il> wrote:

I am having brain freeze right now and was hoping someone could help me
with a (fairly) simple query.

I need to join on the next row in a similar table with specific criteria.

I have a table with events per employee.
I need to have a query that gives per employee each event and the event
after it if it happened on the same day.

The Events table structure is:

EventID
Employee
EventDate
EventTime
EventType

I want my query resultset to be
Employee,EventDate(1),EventTime(1),EventType(1),EventTime(2),EventType(2)
Where Event(2) is the first event of the employee that took place after
the other event.

Example
EventID Employee EventDate EventTime EventType
1 John 6/15/2006 7:00 A
2 Frank 6/15/2006 7:15 B
3 Frank 6/15/2006 7:17 C
4 John 6/15/2006 7:20 C
5 Frank 6/15/2006 7:25 D
6 John 6/16/2006 7:00 A
7 John 6/16/2006 8:30 R

Expected Results
John, 6/15/2006, 7:00, A, 7:20, C
Frank, 6/15/2006, 7:15, B, 7:17, C
Frank, 6/15/2006, 7:17, C, 7:25, D
John, 6/16/2006, 7:00, A, 8:30, R

To get this result set it would have to be an inner join on employee and
date where the second event time is greater then the first. But I don't
want the all of the records with a greater time, just the first event
after.

Thank You
Sim

---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo@postgresql.org so that your
message can get through to the mailing list cleanly

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

#4Sim Zacks
sim@compulab.co.il
In reply to: Gurjeet Singh (#2)
Re: join on next row

Thank you for responding.
I was thinking along those lines as well, though that would be an
absolute performance killer.

Gurjeet Singh wrote:

Show quoted text

It would have been quite easy if done in Oracle's 'lateral view'
feature. But I think it is achievable in standard SQL too; using
subqueries in the select-clause.

Try something like this:

select
Employee, EventDate,
EventTime as e1_time,
EventType as e1_type,
( select
EventTime
from
Events
where Employee = O.Employee
and EventDate = O.EventDate
and EventTime > O.EventTime
limit 1
)as e_time_1,
( select
EventType
from
Events
where Employee = O.Employee
and EventDate = O.EventDate
and EventTime > O.EventTime
limit 1
)
from
Events

Hope it helps...

Regards,
Gurjeet.

On 6/20/06, Sim Zacks <sim@compulab.co.il> wrote:

I am having brain freeze right now and was hoping someone could help me
with a (fairly) simple query.

I need to join on the next row in a similar table with specific criteria.

I have a table with events per employee.
I need to have a query that gives per employee each event and the event
after it if it happened on the same day.

The Events table structure is:

EventID
Employee
EventDate
EventTime
EventType

I want my query resultset to be
Employee,EventDate(1),EventTime(1),EventType(1),EventTime(2),EventType(2)
Where Event(2) is the first event of the employee that took place after
the other event.

Example
EventID Employee EventDate EventTime EventType
1 John 6/15/2006 7:00 A
2 Frank 6/15/2006 7:15 B
3 Frank 6/15/2006 7:17 C
4 John 6/15/2006 7:20 C
5 Frank 6/15/2006 7:25 D
6 John 6/16/2006 7:00 A
7 John 6/16/2006 8:30 R

Expected Results
John, 6/15/2006, 7:00, A, 7:20, C
Frank, 6/15/2006, 7:15, B, 7:17, C
Frank, 6/15/2006, 7:17, C, 7:25, D
John, 6/16/2006, 7:00, A, 8:30, R

To get this result set it would have to be an inner join on employee and
date where the second event time is greater then the first. But I don't
want the all of the records with a greater time, just the first event
after.

Thank You
Sim

---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo@postgresql.org so that your
message can get through to the mailing list cleanly

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

#5Martijn van Oosterhout
kleptog@svana.org
In reply to: Sim Zacks (#4)
Re: join on next row

On Tue, Jun 20, 2006 at 05:13:50PM +0200, Sim Zacks wrote:

Thank you for responding.
I was thinking along those lines as well, though that would be an
absolute performance killer.

I shouldn't be too bad, if you have the appropriate indexes defined.

However, it seems to me this is the kind of problem that is solved
trivially in a function. You simply store the previous row and when you
get the next one you output both.

Have a nice day,
--
Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/

Show quoted text

From each according to his ability. To each according to his ability to litigate.

#6Harald Fuchs
hf0406x@protecting.net
In reply to: Sim Zacks (#1)
Re: join on next row

In article <e780u8$1h5e$1@news.hub.org>,
Sim Zacks <sim@compulab.co.il> writes:

I want my query resultset to be
Employee,EventDate(1),EventTime(1),EventType(1),EventTime(2),EventType(2)
Where Event(2) is the first event of the employee that took place
after the other event.

Example
EventID Employee EventDate EventTime EventType
1 John 6/15/2006 7:00 A
2 Frank 6/15/2006 7:15 B
3 Frank 6/15/2006 7:17 C
4 John 6/15/2006 7:20 C
5 Frank 6/15/2006 7:25 D
6 John 6/16/2006 7:00 A
7 John 6/16/2006 8:30 R

Expected Results
John, 6/15/2006, 7:00, A, 7:20, C
Frank, 6/15/2006, 7:15, B, 7:17, C
Frank, 6/15/2006, 7:17, C, 7:25, D
John, 6/16/2006, 7:00, A, 8:30, R

To get this result set it would have to be an inner join on employee
and date where the second event time is greater then the first. But I
don't want the all of the records with a greater time, just the first
event after.

You can filter the others out by an OUTER JOIN:

SELECT e1.Employee, e1.EventDate,
e1.EventTime, e1.EventType,
e2.EventTime, e2.EventType
FROM events e1
JOIN events e2 ON e2.Employee = e1.Employee
AND e2.EventDate = e1.EventDate
AND e2.EventTime > e1.EventTime
LEFT JOIN events e3 ON e3.Employee = e1.Employee
AND e3.EventDate = e1.EventDate
AND e3.EventTime > e1.EventTime
AND e3.EventTime < e2.EventTime
WHERE e3.EventID IS NULL
ORDER BY e1.EventDate, e1.EventTime

#7Aaron Evans
aaron@aarone.org
In reply to: Gurjeet Singh (#3)
Re: join on next row

sorry to nitpick, but I think that to get this query to do exactly
what you want you'll need to add ordering over EventTime on your sub-
selects to assure that you get the next event and not just some event
later event on the given day.

-ae

On Jun 20, 2006, at 11:12 AM, Gurjeet Singh wrote:

Show quoted text

Gurjeet Singh wrote:

It would have been quite easy if done in Oracle's 'lateral view'
feature. But I think it is achievable in standard SQL too; using
subqueries in the select-clause.

Try something like this:

select
Employee, EventDate,
EventTime as e1_time,
EventType as e1_type,
( select
EventTime
from
Events
where Employee = O.Employee
and EventDate = O.EventDate
and EventTime > O.EventTime
limit 1
)as e_time_1,
( select
EventType
from
Events
where Employee = O.Employee
and EventDate = O.EventDate
and EventTime > O.EventTime
limit 1
)
from
Events

Hope it helps...

Regards,
Gurjeet.

Attachments:

smime.p7sapplication/pkcs7-signature; name=smime.p7sDownload
#8Sim Zacks
sim@compulab.co.il
In reply to: Harald Fuchs (#6)
Re: join on next row

Harold,
That's brilliant.
Sim

Harald Fuchs wrote:

Show quoted text

In article <e780u8$1h5e$1@news.hub.org>,
Sim Zacks <sim@compulab.co.il> writes:

I want my query resultset to be
Employee,EventDate(1),EventTime(1),EventType(1),EventTime(2),EventType(2)
Where Event(2) is the first event of the employee that took place
after the other event.

Example
EventID Employee EventDate EventTime EventType
1 John 6/15/2006 7:00 A
2 Frank 6/15/2006 7:15 B
3 Frank 6/15/2006 7:17 C
4 John 6/15/2006 7:20 C
5 Frank 6/15/2006 7:25 D
6 John 6/16/2006 7:00 A
7 John 6/16/2006 8:30 R

Expected Results
John, 6/15/2006, 7:00, A, 7:20, C
Frank, 6/15/2006, 7:15, B, 7:17, C
Frank, 6/15/2006, 7:17, C, 7:25, D
John, 6/16/2006, 7:00, A, 8:30, R

To get this result set it would have to be an inner join on employee
and date where the second event time is greater then the first. But I
don't want the all of the records with a greater time, just the first
event after.

You can filter the others out by an OUTER JOIN:

SELECT e1.Employee, e1.EventDate,
e1.EventTime, e1.EventType,
e2.EventTime, e2.EventType
FROM events e1
JOIN events e2 ON e2.Employee = e1.Employee
AND e2.EventDate = e1.EventDate
AND e2.EventTime > e1.EventTime
LEFT JOIN events e3 ON e3.Employee = e1.Employee
AND e3.EventDate = e1.EventDate
AND e3.EventTime > e1.EventTime
AND e3.EventTime < e2.EventTime
WHERE e3.EventID IS NULL
ORDER BY e1.EventDate, e1.EventTime

---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

#9Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: Aaron Evans (#7)
Re: join on next row

Thanks for pointing it out.... You are right; I forgot to add that...

Show quoted text

On 6/20/06, Aaron Evans <aaron@aarone.org> wrote:

sorry to nitpick, but I think that to get this query to do exactly
what you want you'll need to add ordering over EventTime on your sub-
selects to assure that you get the next event and not just some event
later event on the given day.

-ae

On Jun 20, 2006, at 11:12 AM, Gurjeet Singh wrote:

Gurjeet Singh wrote:

#10Merlin Moncure
mmoncure@gmail.com
In reply to: Harald Fuchs (#6)
Re: join on next row

On 20 Jun 2006 18:20:55 +0200, Harald Fuchs <hf0406x@protecting.net> wrote:

In article <e780u8$1h5e$1@news.hub.org>,
Sim Zacks <sim@compulab.co.il> writes:

To get this result set it would have to be an inner join on employee
and date where the second event time is greater then the first. But I
don't want the all of the records with a greater time, just the first
event after.

You can filter the others out by an OUTER JOIN:

SELECT e1.Employee, e1.EventDate,
e1.EventTime, e1.EventType,
e2.EventTime, e2.EventType
FROM events e1
JOIN events e2 ON e2.Employee = e1.Employee
AND e2.EventDate = e1.EventDate
AND e2.EventTime > e1.EventTime
LEFT JOIN events e3 ON e3.Employee = e1.Employee
AND e3.EventDate = e1.EventDate
AND e3.EventTime > e1.EventTime
AND e3.EventTime < e2.EventTime
WHERE e3.EventID IS NULL
ORDER BY e1.EventDate, e1.EventTime

This will only give the correct answer if the next event is on the
same day. This does not match the problem as stated. The actual
answer is more complex than it looks (in < pg 8.2). In pg 8.2, you
can make:

SELECT e1.Employee, e1.EventDate,
e1.EventTime, e1.EventType,
e2.EventTime, e2.EventType
FROM events e1
JOIN events e2 ON
(e2.Employee, e2.EventDate, e2.EventTime) >
(e1.Employee, e1.EventDate, e1.EventTime)
LEFT JOIN events e3 ON
(e3.Employee, e3.EventDate, e3.EventTime) >
(e1.Employee, e1.EventDate, e1.EventTime) AND
e3.EventTime < e2.EventTime
WHERE e3.EventID IS NULL
ORDER BY e1.EventDate, e1.EventTime

if you only want answers that match the same date as the selected
event, harald's answer is correct. to get the correct answer in 8.1
and down you must make a monster of a sql statement ;)

merlin

#11Sim Zacks
sim@compulab.co.il
In reply to: Merlin Moncure (#10)
Re: join on next row

Merlin,

Thank you for your input. My original question did specifically mention
that the events had to be on the same day.

I need to have a query that gives per employee each event and the event after it if it happened _on the same day_.

Secondly, I hadn't seen that syntax in 8.2 yet. That is funky cool and I
will certainly be using it in the future.

Thanks
Sim

Merlin Moncure wrote:

Show quoted text

On 20 Jun 2006 18:20:55 +0200, Harald Fuchs <hf0406x@protecting.net> wrote:

In article <e780u8$1h5e$1@news.hub.org>,
Sim Zacks <sim@compulab.co.il> writes:

To get this result set it would have to be an inner join on employee
and date where the second event time is greater then the first. But I
don't want the all of the records with a greater time, just the first
event after.

You can filter the others out by an OUTER JOIN:

SELECT e1.Employee, e1.EventDate,
e1.EventTime, e1.EventType,
e2.EventTime, e2.EventType
FROM events e1
JOIN events e2 ON e2.Employee = e1.Employee
AND e2.EventDate = e1.EventDate
AND e2.EventTime > e1.EventTime
LEFT JOIN events e3 ON e3.Employee = e1.Employee
AND e3.EventDate = e1.EventDate
AND e3.EventTime > e1.EventTime
AND e3.EventTime < e2.EventTime
WHERE e3.EventID IS NULL
ORDER BY e1.EventDate, e1.EventTime

This will only give the correct answer if the next event is on the
same day. This does not match the problem as stated. The actual
answer is more complex than it looks (in < pg 8.2). In pg 8.2, you
can make:

SELECT e1.Employee, e1.EventDate,
e1.EventTime, e1.EventType,
e2.EventTime, e2.EventType
FROM events e1
JOIN events e2 ON
(e2.Employee, e2.EventDate, e2.EventTime) >
(e1.Employee, e1.EventDate, e1.EventTime)
LEFT JOIN events e3 ON
(e3.Employee, e3.EventDate, e3.EventTime) >
(e1.Employee, e1.EventDate, e1.EventTime) AND
e3.EventTime < e2.EventTime
WHERE e3.EventID IS NULL
ORDER BY e1.EventDate, e1.EventTime

if you only want answers that match the same date as the selected
event, harald's answer is correct. to get the correct answer in 8.1
and down you must make a monster of a sql statement ;)

merlin

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

#12Merlin Moncure
mmoncure@gmail.com
In reply to: Sim Zacks (#11)
Re: join on next row

On 6/25/06, Sim Zacks <sim@compulab.co.il> wrote:

Merlin,

Thank you for your input. My original question did specifically mention
that the events had to be on the same day.

I need to have a query that gives per employee each event and the event after it if it happened _on the same day_.

whoop! :) oh well. heh