1

I have a three different tables that I'm trying to join up correctly but I'm running into some issues.

Here are the tables

  1. Train: Listing of trains (choo-choooo) and train length in number of wagons
  2. WTA: Wagon Tonnes A - Weight of wagons in train at Location A
  3. WTB: Wagon Tonnes B - Weight of wagons in train at Location B

The issue: Some entire Trains are missing randomly from either/or/both of the WagonTonnes tables. Some individual wagons are missing from the the WagonTonnes tables. And I want my query to show those cases as null where missing.

I first tried doing this and it works fine.

select 
 train.id,
 train.length,
 a.position_in_train
 a.tonnes,
from 
 train
 left outer join wta a
 using (train_id)

Now I want to add a left outer join for b, like so

select 
 train.id,
 train.length,
 a.position_in_train
 a.tonnes,
 b.position_in_train,
 b.tonnes
from 
 train
 left outer join wta a
 using (train_id)
 left outer join wtb b
 using (train_id)

But this goes haywire and repeats the same row result over and over.

Proposed Solution

I suspect that I somehow need to get a query from train that instead of looking like so,

train.id train.length
7        163 

looks like this instead

train.id train.position
7        1 
7        2 
7        3
7        4
...      ...
7        162
7        163

And then rewrite my joins to look like this:

left outer join wta a
on (a.train_id = train.train_id and a.position = train.position)

Question 1: Is my general approach to this problem correct? (join-wise)

Question 2: Is my solution correct? If so, how can I implement it?

Tommy O'Dell
  • 7,019
  • 13
  • 56
  • 69

1 Answers1

3

Your approach will work, but I think it is easier to LEFT JOIN to a combined dataset representing the superset of WTA and WTB. The two-part UNION ALL emulates FULL JOIN that is lacking in MySQL.

select 
 t.id,
 t.length,
 wt.a_position_in_train,
 wt.a_tonnes,
 wt.b_position_in_train,
 wt.b_tonnes
from train t
left join (
    select a.train_id,
        a.position_in_train a_position_in_train, a.tonnes b_tonnes,
        b.position_in_train b_position_in_train, b.tonnes b_tonnes
    from wta a left join wtb b on a.train_id = b.train_id and a.position_in_train = b.position_in_train
    union all
    select b.train_id, a.position_in_train, a.tonnes, b.position_in_train, b.tonnes
    from wta b left join wtb a on a.train_id = b.train_id and a.position_in_train = b.position_in_train
    where a.train_id is null
) wt on t.train_id = wt.train_id
order by t.train_id, coalesce(a_position_in_train, b_position_in_train)

Brain freeze, for Oracle, the FULL JOIN would be (inner query)

    select coalesce(a.train_id, b.train_id) train_id,
        a.position_in_train a_position_in_train, a.tonnes b_tonnes,
        b.position_in_train b_position_in_train, b.tonnes b_tonnes
    from wta a full join wtb b
        on a.train_id = b.train_id and a.position_in_train = b.position_in_train
RichardTheKiwi
  • 105,798
  • 26
  • 196
  • 262
  • That's awesome :) I'm working with oracle so I should be able to use a full join. Can you suggest how that would change the SQL you've written? – Tommy O'Dell Mar 31 '11 at 02:53