Соединение влево не тянет через нули, где ожидается - PullRequest
0 голосов
/ 14 декабря 2009

У меня есть запрос, который выглядит примерно так (я изменил имена таблиц):

select @user_id
,      isnull(ur.rule_value, isnull(manr.rule_value, def.rule_value)) [rule_value]
,      isnull(urt.name, isnull(manrt.name, def.name)) [rule_type]
from   (select @user_id [user_id]
        , rule.rule_value
        , rule_type.name
        from rule
        join rule_type on rule_type.rule_type_id = rule.rule_type_id
        where rule.user_id = 1) def
join   user on user.user_id = def.user_id
join   manager man on man.manager_id = user.manager_id
left join rule ur on ur.user_id = user.user_id
left join rule_type urt on urt.rule_type_id = ur.rule_type_id
left join rule manr on manr.manager_id = man.manager_id
left join rule_type manrt on manrt.rule_type_id = manr.rule_type_id

Я ожидаю, что когда нет правила для пользователя или менеджера пользователя, тогда следует использовать правило по умолчанию. Тем не менее, я получаю результат, только если у пользователя есть правило.

Я пытался left join использовать все, но безрезультатно, и оператор select для таблицы def возвращает все правила по умолчанию.

Что я делаю не так?

@user_id является переменной.

Обновление

Пример схемы

rule
rule_id user_id manager_id rule_value
1       1       1           27
2       1       1           24
3       1       1           25
4       1       1           44
5       1       1           88
1       2       4           2
2       2       4           23
3       2       4           18
3       NULL    4           19
4       NULL    4           20
5       NULL    4           21


rule_type
rule_id name
1       'Craziness'
2       'Number of legs'
3       'Hair ranking'
4       'Banana preference'
5       'Rule 5'

user
user_id manager_id ... other columns
1       1
2       4
3       4

manager
manager_id ... other columns
1
2
3
4
5
6

Так что, если @user_id равно 2, то я ожидаю, что на выходе

2, 2, 'Craziness'
2, 23, 'Number of legs'
2, 18, 'Hair ranking'
2, 20, 'Banana preference'
2, 21, 'Rule 5'

Но если @user_id равен 3, то я ожидаю, что на выходе

3, 27, 'Craziness'
3, 24, 'Number of legs'
3, 19, 'Hair ranking'
3, 20, 'Banana preference'
3, 21, 'Rule 5'

Ответы [ 4 ]

1 голос
/ 14 декабря 2009

Я разделил запрос на две части.

Я думаю, что из-за того, что структуры таблиц более сложны, чем я поставил в исходном вопросе, это означает, что ответа CodeByMoonlight недостаточно, это дало мне повторяющиеся строки, которые я не мог объяснить.

Мое решение заключается в следующем (в отношении деталей, которые я дал в вопросе):

create table #user_rules
(
 user_id int,
 rule_value int,
 rule_type varchar(255),
 rule_type_id,
)
--Insert default values
insert into #user_rules
select @user_id [user_id]
    , rule.rule_value
    , rule_type.name
    , rule_type.rule_type_id
from rule
join rule_type on rule_type.rule_type_id = rule.rule_type_id
where rule.user_id = 1
--Update table with any available values
update #user_rules
set rule_value = ur.rule_value
from user u
join manager m on u.manager_id = m.manager_id
join rule ur on ur.user_id = u.user_id or (ur.manager_id = man.manager_id and ur.user_id is null)
join rule_type urt on urt.rule_type_id = ur.rule_type_id
where urt.rule_type_id = #urse_rules.rule_type_id
and u.user_id = @user_id
1 голос
/ 14 декабря 2009

Чтобы ответить на вопрос в заголовке, левое соединение не действует как обычное соединение. LEFT JOIN - это то же самое, что и LEFT OUTER JOIN, что означает также возврат записей в таблице LEFT, которые не соответствуют критериям ON.

1 голос
/ 14 декабря 2009

Избавьтесь от этого:

left join rule ur on ur.user_id = user.user_id
left join rule_type urt on urt.rule_type_id = ur.rule_type_id
left join rule manr on manr.manager_id = man.manager_id
left join rule_type manrt on manrt.rule_type_id = manr.rule_type_id

и замените его следующим:

left join rule ur on ur.user_id = user.user_id or ur.user_id = man.manager_id
left join rule_type urt on urt.rule_type_id = ur.rule_type_id

затем измените открывающий SELECT на:

select @user_id
,      isnull(ur.rule_value, def.rule_value) [rule_value]
,      isnull(urt.name, def.name) [rule_type]

По сути, вы неправильно делаете, что у вас есть одна сущность (user-manager-default), и вы пытаетесь связать ее с другой сущностью (правилом) с помощью двух разных объединений. Если одно соединение не работает, а другое работает, не найден соответствующий NULL для вашего ISNULL, чтобы найти. Это немного нелогично.

1 голос
/ 14 декабря 2009

Обычное соединение - это фактически левое внутреннее соединение. На самом деле вам нужно внешнее соединение, которое извлекает результат, даже если оно не может соединить его с другой таблицей.

...