左连接没有拉到预期的空值

时间:2009-12-14 12:27:35

标签: sql left-join default-value

我有一个看起来像这样的查询(我已经更改了表名):

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但无效,而def表的select语句会带回所有默认规则。

我做错了什么?

@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_id2,那么我希望输出

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 个答案:

答案 0 :(得分:1)

常规联接实际上是左内联接。你真正想要的是一个外部联接,它获取结果,即使它不能与其他表连接。

答案 1 :(得分:1)

要回答标题中的问题,LEFT JOIN不会像常规JOIN那样行事。 LEFT JOIN与LEFT OUTER JOIN相同,这意味着还将返回LEFT表中与ON标准不匹配的记录。

答案 2 :(得分:1)

摆脱这个:

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查找。这有点违反直觉。

答案 3 :(得分:1)

我将查询分为两部分。

我认为因为表格结构比原始问题更复杂,这意味着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