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.
id name order_by
5 A 1
6 B 2
7 C 3
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
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
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
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?
The order doesn't matter for INNER joins but the order matters for (LEFT, RIGHT or FULL) OUTER joins. Outer joins are not commutative.
LEFT JOIN is also known as LEFT OUTER JOIN. Syntax: SELECT table1.column1,table1.column2,table2.column1,....
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.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With