views:

76

answers:

5

I have a table similar to the following (of course with more rows and fields):

category_id | client_id | date        | step
     1            1       2009-12-15    first_step
     1            1       2010-02-03    last_step

     1            2       2009-04-05    first_step
     1            2       2009-08-07    last_step

     2            3       2009-11-22    first_step

     3            4       2009-11-14    first_step
     3            4       2010-05-09    last_step

I would like to transform this so that I can calculate the time between the first and last steps and eventually find the average time between first and last steps, etc. Basically, I'm stumped at how to transform the above table into something like:

category_id | first_date | last_date
     1        2009-12-15   2010-02-03
     1        2009-04-05   2009-08-07
     2        2009-11-22   NULL
     3        2009-11-14   2010-05-09

Any help would be appreciated.

With OMG Ponies help, here's the solution:

SELECT t.category_id,
     MIN(t.date) AS first_date,
     CASE 
       WHEN COUNT(*) >= 2 THEN MAX(t.date)
       ELSE NULL
     END AS last_date
FROM TABLE t
GROUP BY t.category_id, t.client_id
+1  A: 

a simple GROUP BY should do the trick

SELECT   category_id
         , MIN(first_date)
         , MAX(last_date)
    FROM TABLE
GROUP BY category_ID
Svetlozar Angelov
+1: But you were missing the FROM clause
OMG Ponies
Yes, as long as I change the GROUP BY clause to: GROUP BY category_id, client_id this works.
Mitchell
I just realized it doesn't flag the last_date as NULL when there is no last_date.
Mitchell
+4  A: 

Updated based on question update/clarification:

  SELECT t.category_id,
         MIN(t.date) AS first_date,
         CASE 
           WHEN MAX(t.date) = MIN(t.date) THEN NULL 
           ELSE MAX(t.date)
         END AS last_date
    FROM TABLE t
GROUP BY t.category_id, t.client_id
OMG Ponies
I may have oversimplified my example, so I've changed it. There are many entries per category.
Mitchell
Ok, as long as I change the GROUP BY clause to: GROUP BY t.category_id, t.client_id this works.
Mitchell
@Mitchell: Updated, thx for updating the expected results.
OMG Ponies
Actually, I just realized it doesn't flag the last_date as NULL when there is no last_date.
Mitchell
@Mitchell: Right - sorry about that, fixed.
OMG Ponies
You're on the right track. How about the following? It has the advantage that if min and max date are actually both the same, then last_date will be filled in.SELECT t.category_id, MIN(t.date) AS first_date, IF ((COUNT(*) = 2), MAX(t.date), NULL) AS last_date FROM TABLE tGROUP BY t.category_id, t.client_id
Mitchell
OMG Ponies
Although in my particular case in can never be > 2, I think you're right that >= 2 is the better general solution. What part of the query is not ANSI compatible?
Mitchell
@Mitchell: I see - The `IF` isn't - CASE expressions are ANSI. I really prefer CASE/SWITCH statements over IF syntax any day...
OMG Ponies
I didn't realize IF statements are not ANSI. Coming from a language programming background, IF statements are pretty universal. I've added the solution with the CASE statement. Thanks for all your help.
Mitchell
@Mitchell: CASE may seem overkill for a simple IF, but it accommodate multiple IF/ELSE more elegantly. Oracle's DECODE is ugly at first glance in comparison...
OMG Ponies
A: 

simple answer:

  SELECT fist.category_id, first.date, last.date
    FROM tableName first
    LEFT JOIN tableName last
        ON first.category_id = last.category_id
        AND first.step = 'first_step'
        AND last.step ='last_step'

You could also do the calculations in the query instead of just returning the two date values.

kniemczak
This will actually give every combination of dates for each category out there.
Tom H.
You are right...thats what I get for going too fast. Thanks for catching that.
kniemczak
Yes, I just tried and it gives a lot of results
Mitchell
Just looked and another column has been added (client_id) so this query would not work with that change.
kniemczak
+1  A: 

Try:

select
    category_id
    , min(date) as first_date
    , max(date) as last_date
from
    table_name
group by
    category_id
    , client_id
wshato
I may have oversimplified my example, so I've changed it. There are many entries per category.
Mitchell
Yes, as long as I change the GROUP BY clause to: GROUP BY category_id, client_id this works.
Mitchell
Good. I updated my query to reflect your changes.
wshato
I just realized it doesn't flag the last_date as NULL when there is no last_date.
Mitchell
See thread with OMG Ponies.
Mitchell
A: 

You need to do two sub queries and then join them together - something like the following

select * from (select *, date as first_date from table where step = "first_step") a left join ( select * date as last_date from table where step = "lastt_step") b on (a.category_id = b.category_id)

Enjoy!

Doug
I just tried it and like kniemczak's answer, I think it gives every combination of dates.
Mitchell