Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LEFT OUTER JOIN with conditions (where, order by)?

I'm working on a Rails3 project with MySql (local) and Postgresql (Heroku) databases.
I need to put conditions on a LEFT OUTER JOIN but I don't know how.

I have 2 tables TRAININGS and TRAINING_HISTORIES.
I want to retrieve all the records of TRAININGS and add the last valid (aka finished) associated record of TRAINING_HISTORIES.

table TRAININGS

id  name  order_by
5   A     1  
6   B     2  
7   C     3

table TRAINING_HISTORIES

id  training_id finished_at score
43  5           2011-06-06  10
44  5           null        null
45  6           2011-07-07  11
46  6           2011-08-08  14
47  6           null        null
48  6           2011-09-09  18
49  6           null        null
50  7           null        null
51  7           2011-10-10  19

Here's my SQL query :

SELECT tc.id, tc.name, tc.order, 
th.id as history_id, th.finished_at, th.score
FROM trainings tc
LEFT OUTER JOIN training_histories th ON th.training_id = tc.id
WHERE tc.id > 4
AND tc.id < 8
GROUP BY tc.id
ORDER BY tc.order_by ASC, tc.id ASC

RESULTS I HAVE :

id  name  order history_id  finished_at score
5   A     1     43          2011-06-06  10
6   B     2     45          2011-07-07  11
7   C     3     50          null        null
  • The query retrieve the first training_history for each join

RESULTS I NEED :

id  name  order history_id  finished_at score
5   A     1     43          2011-06-06  10
6   B     2     48          2011-09-09  18
7   C     3     51          2011-10-10  19
  • In this scenario : it's the last finished training_history who's retrieved...

Any suggestions really appreciated !

Thank you

EDIT: If someone can answer on the Rails part, it could be great too ;-)
How to Convert SQL Query to Rails Active Record Query?

like image 332
fro_oo Avatar asked Aug 10 '11 18:08

fro_oo


People also ask

Does the order of the on condition of a left join matter?

The order doesn't matter for INNER joins but the order matters for (LEFT, RIGHT or FULL) OUTER joins. Outer joins are not commutative.

What is the correct query for left outer join?

LEFT JOIN is also known as LEFT OUTER JOIN. Syntax: SELECT table1.column1,table1.column2,table2.column1,....

How left outer join works with example?

A left outer join is a method of combining tables. The result includes unmatched rows from only the table that is specified before the LEFT OUTER JOIN clause. If you are joining two tables and want the result set to include unmatched rows from only one table, use a LEFT OUTER JOIN clause or a RIGHT OUTER JOIN clause.

What does (+) mean in SQL join?

The plus sign is Oracle syntax for an outer join. There isn't a minus operator for joins. An outer join means return all rows from one table. Also return the rows from the outer joined where there's a match on the join key. If there's no matching row, return null.


2 Answers

Try this Query, it would give you each training and the most recent training history for each one:

SELECT tc.id, tc.name, tc.order, 
th.id as history_id, th.finished_at, th.score
FROM trainings tc
LEFT OUTER JOIN training_histories th ON th.training_id = tc.id 
    and th.id =
    (SELECT th1.id from training_histories th1 where th1.training_id = tc.id
     and th1.finished_at is not null
     order by th1.finished_at desc limit 1)
WHERE tc.id > 4
AND tc.id < 8
GROUP BY tc.id
ORDER BY tc.order_by ASC, tc.id ASC
like image 175
everton Avatar answered Oct 20 '22 18:10

everton


I'm quite sure you can do

SELECT tc.id, tc.name, tc.order, 
th.id as history_id, th.finished_at, th.score
FROM trainings tc
LEFT OUTER JOIN (SELECT id, training_id, MAX(finished_at) as finished_at, score 
    FROM training_histories GROUP BY training_id) th ON th.training_id = tc.id
WHERE tc.id > 4
AND tc.id < 8
GROUP BY tc.id
ORDER BY tc.order_by ASC, tc.id ASC
like image 43
joakimdahlstrom Avatar answered Oct 20 '22 17:10

joakimdahlstrom