tags:

views:

96

answers:

2

I have a log table with the following format (and sample data):

  date     |  time
2010/01/02 | 10:00
2010/01/02 | 13:00
2010/01/04 | 02:34

I want to make an SQL query that will retrieve results with the following format:

date1      | time1 | date2      | time2
2010/01/02 | 10:00 | 2010/01/02 | 13:00
2010/01/02 | 13:00 | 2010/01/04 | 02:34
2010/01/04 | 02:34 | <null>     | <null>

So I was thinking a left outer join would do the trick:

SELECT
  i.date as date1,
  i.time as time1,
  j.date as date2,
  j.time as time2
FROM
  log_table i
  LEFT OUTER JOIN
    log_table j
  ON
    i.id = j.id
    AND (j.date > i.date
    OR (j.date == i.date AND j.time > i.time))

However, this would result in the following:

date1      | time1 | date2      | time2
2010/01/02 | 10:00 | 2010/01/02 | 13:00
2010/01/02 | 10:00 | 2010/01/04 | 02:34
2010/01/02 | 13:00 | 2010/01/04 | 02:34
2010/01/04 | 02:34 | <null>     | <null>

The database used is PostgreSql by the way.

Thanks.

+3  A: 

In PostgreSQL 8.4:

SELECT  date AS date1, time AS time1,
        LEAD(date) OVER (ORDER BY date, time, id) AS date2,
        LEAD(time) OVER (ORDER BY date, time, id) AS time2
FROM    log_table
ORDER BY
        date, time, id

, or just this:

SELECT  date1, time1, (lnext).*
FROM    (
        SELECT  date AS date1, time AS time1,
                LEAD(lt) OVER (ORDER BY date, time, id) AS lnext
        FROM    log_table lt
        ) q
ORDER BY
        date, time, id

In PostgreSQL 8.3 and below:

SELECT  date AS date1, time AS time1,
        (li).date AS date2, (li).time AS time2
FROM    (
        SELECT  lo.*,
                (
                SELECT  li
                FROM    log_table li
                WHERE   (li.date, li.time, li.id) > (lo.date, lo.time, lo.id)
                ORDER BY
                        date, time, id
                LIMIT 1
                ) AS li
        FROM    log_table lo
        ) q
Quassnoi
@ijw yup, 'i' and 'j' are basically the same tables. if the rows were sorted in order according to date and time, i want a row to be paired with the row after it
absolute0
@Quassnoi it's the first time i heard about lead over, if i have other columns in 'i' and 'j' aside from the date and time, will it work as well?
absolute0
@absolute0: Yes, it will. In PostgreSQL, you can select a whole record in one field and explode it in the upper-level query or on client side.
Quassnoi
@Quassnoi unfortunately, we're using PostgreSQL 8.1, i'll try your other suggestion
absolute0
@Quassnoi, the PostgreSQl 8.3 and below suggestion didn't work but on a whim, I changed this part of my original sql: "AND (j.date > i.date OR (j.date == i.date AND j.time > i.time))" into the syntax you used: "AND (j.date, j.time) > (i.date, i.time)" and for some reasons, it works as I desired it to... first time for me to encounter this syntax too. Thanks!
absolute0
A: 
SELECT 
  i.date as date1, 
  i.time as time1, 
  min(j.date) as date2, 
  min(j.time) as time2 
FROM 
  log_table i 
  LEFT OUTER JOIN 
    log_table j 
  ON 
    i.id = j.id 
    AND (j.date > i.date 
    OR (j.date == i.date AND j.time > i.time)) 
GROUP BY i.date, i.time
HLGEM