问题
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?
回答1:
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
回答2:
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
回答3:
Also in the where condition check for finished_at not null and add Order by finished_at DESC
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
AND th.finished_at IS NOT NULL
GROUP BY tc.id
ORDER BY tc.order_by ASC, tc.id ASC, th.finished_at DESC
来源:https://stackoverflow.com/questions/7015839/left-outer-join-with-conditions-where-order-by