2016-03-30 1 views
1

Я соединяю две таблицы на трех полях. Проблема, с которой я столкнулась, заключается в том, что мне нужно использовать строку по умолчанию из таблицы b, если a.baz не находится в b.baz. Проблема в том, что некоторые из них будут иметь совпадение в b, но также имеют значение по умолчанию, и это вызывает перекрестный продукт, который я не хочу.Соедините значения по умолчанию, но не желая перекрестного продукта

select a.foo, a.bar, a.baz, b.fee, b.fie 
from a 
join b 
on a.foo = b.foo 
and a.bar = b.bar 
and ((a.baz = b.baz) or b.baz = 'DEFAULT') 

Токовый выход:

foo bar baz fee fie 
bob doe NYC 500 200 
bob doe DEFUALT 100 100 
john doe DEFAULT 100 100 
jane doe NYC 500 500 

желаемый результат:

foo bar baz fee fie 
bob doe NYC 500 200 
john doe DEFAULT 100 100 
jane doe NYC 500 500 

Образец данных:

a: foo bar baz bob doe NYC john doe NYC jane doe NYC

b: foo bar baz fee fie bob doe NYC 500 200 bob doe DEFAULT 100 100 john doe CHI 300 200 john doe DEFAULT 100 100 jane doe NYC 500 100

+2

Вы можете показать некоторые данные образца из таблиц? –

+0

Добавлены некоторые примеры данных. – SparkeyG

+1

результат, который вы получаете, не является перекрестным продуктом. Я думаю, ваш текущий выход правильный, с учетом условий. –

ответ

2

Вы должны добавить NOT EXISTS таким образом, чтобы исключить b запись, имеющую baz = 'DEFAULT' когда матч a.baz = b.baz также существует:

select a.foo, a.bar, a.baz, b.baz, b.fee, b.fie 
from a 
join b 
on a.foo = b.foo and a.bar = b.bar and ((a.baz = b.baz) OR b.baz = 'DEFAULT') 
where not exists (select 1 
        from b as b1 
        where a.foo = b1.foo and 
         a.bar = b1.bar and 
         b.baz = 'DEFAULT' and 
         b1.baz = a.baz) 

Demo here

+0

Спасибо, что сделал трюк. – SparkeyG

0

Ваш запрос вполне нормально, так как она уже содержит строки вы хотите. Теперь вы должны удалить ненужные строки. Вы делаете это, оценивая свои матчи и поддерживая только лучшее совпадение. Это может быть сделано с ROW_NUMBER, что дает лучшую запись строки номер 1.

select foo, bar, abaz, bbaz, fee, fie 
from 
(
    select 
    a.foo, a.bar, a.baz as abaz, b.baz as bbaz, b.fee, b.fie, 
    row_number() over (partition by a.foo, a.bar 
         order by case when b.baz = 'DEFAULT' then 2 else 1 end) as rn 
    from a 
    join b on b.foo = a.foo 
     and b.bar = a.bar 
     and b.baz in (a.baz, 'DEFAULT') 
) ranked 
where rn = 1; 
0

Вот еще один простой способ решить это с помощью внешних соединений:

select 
    a.foo, 
    a.bar, 
    case when b.baz is null then d.baz else b.baz end as baz, 
    case when b.baz is null then d.fee else b.fee end as fee, 
    case when b.baz is null then d.fie else b.fie end as fie 
from a 
left join b on b.foo = a.foo and b.bar = a.bar and b.baz = a.baz 
left join b d on d.foo = a.foo and d.bar = a.bar and d.baz = 'DEFAULT'; 

Если плата и тьфу не обнуляемым, вам может упростить это:

select 
    a.foo, 
    a.bar, 
    coalesce(b.baz, d.baz) as baz, 
    coalesce(b.fee, d.fee) as fee, 
    coalesce(b.fie, d.fie) as fie 
from a 
left join b on b.foo = a.foo and b.bar = a.bar and b.baz = a.baz 
left join b d on d.foo = a.foo and d.bar = a.bar and d.baz = 'DEFAULT'; 

 Смежные вопросы

  • Нет связанных вопросов^_^