如何在SQL中用INNER join替换LEFT外连接?

时间:2017-04-14 05:07:12

标签: sql sql-server database database-design

我有一个视图我需要提供集群索引问题是为了提供集群索引它不应该有任何左外连接或右外连接,我想用INNER连接替换LEFT外连接,我能想到的方法之一就是在右表中插入一个假值-1,即使左表中的所有Ids都不匹配INNER JOIN中右表的Ids,也可以这样做我们在右表中插入了-1并且我们正在使用IsNULL(u.UserId,-1)它应该返回左表中的所有值,但不知何故这种方法不起作用。

create table Users(
UserId int,
UserName nvarchar(255)
)
insert into Users values(1,'sid429')
insert into Users values(2,'ru654')
insert into Users values(3,'dick231')

create table managers
(
caseId int,
CaseName nvarchar(255),
UserId int
)

insert into managers values (100,'Case1',1)
insert into managers values (101,'Case2',2)
insert into managers values (-1,NULL,-1)


select username from users u inner join managers m on  m.UserId=IsNULL(u.UserId,-1)

5 个答案:

答案 0 :(得分:1)

IsNull(u.UserId,-1)似乎没有 - u.UserId永远不会为null,因为缺少数据在manager表中 - 在这种情况下,u.UserId将始终具有值,但是m.UserId可能没有,所以IsNull(u.UserId,-1)不会工作。

我很想看到一个更好的答案,但我认为你不能做到这一点 - 我认为你最终需要有条件地将值替换为-1,如果它不存在于另一张桌子,像这样:

select username from users u
inner join managers m on m.UserId = 
    case when not exists(select * from managers where UserId = u.UserId) 
    then -1 else u.UserId end

这具有预期效果,但查看执行计划,不会对您的性能问题有所帮助。

答案 1 :(得分:0)

不要谈论索引,但我认为您可以LEFT JOIN + INNER JOIN替换UNION

select username from users u inner join managers m on  m.UserId= u.UserId

UNION ALL 

select username from users u WHERE NOT EXISTS (SELECT 1 FROM managers m WHERE m.UserId = u.UserId)

答案 2 :(得分:0)

如果在相关表中添加缺失值,则可以使用INNER JOIN替换LEFT OUTER JOIN。

它没有为您工作,因为您添加了-1值。但是INNER JOIN上的不匹配值是3,而不是null或-1。

您可以在运行时使用UNION执行此操作,无需像您尝试的那样永久创建这些值(插入该值为1):

with expanded_managers as (
    select CaseId, CaseName, UserId
    from managers  
  union
    select null, null, UserId
    from users
    where not exists (select * from managers where managers.UserId = users.UserId)
)

select UserName, CaseName 
from users 
     inner join expanded_managers on expanded_managers.UserId = users.UserId

答案 3 :(得分:0)

如果您只需要用户名,则应该很简单: 从用户中选择不同的用户名。内部联接管理器m on m.UserId = u.UserId OR(m.UserId = -1 AND u.userId = u.userId)

答案 4 :(得分:0)

我已经清理过这部分了。鉴于你没有指定任何约束

,我不得不猜测逻辑模型
create table Users (
  UserId   int           not null
, UserName nvarchar(255) not null

, constraint pk_users primary key (UserId) 
, constraint ak_users unique      (UserName) 
);


create table Cases (
  CaseId   int           not null
, CaseName nvarchar(255) not null
, UserId   int           not null

, constraint pk_cases primary key (CaseId)
, constraint ak_cases unique      (CaseName)
, constraint fk_cases foreign key (UserId)
                 references Users (UserId)
);

insert into Users values(1,'sid429') ;
insert into Users values(2,'ru654')  ;
insert into Users values(3,'dick231');

insert into Cases values (100,'Case1',1);
insert into Cases values (101,'Case2',2);

这主要是不言自明的,但您必须了解结果的候选键(唯一)是:{UserID, CaseId}{UserName, CaseName}{UserID, CaseName}{UserName, CaseId}。不确定你是否在期待。

with
R_00 as (
    select UserId from Users
    except
    select UserId from Cases
)
select u.UserId
     , u.UserName
     , c.CaseId
     , c.CaseName    
from Users as u
join Cases as c on u.UserId = c.UserId

union

select u.UserId
     , u.UserName
     , (-1) as CaseId
     , 'n/a'as CaseName 
from Users as u
join R_00  as r on r.UserId = u.UserID
;

此版本的另一个版本,类似于帖子中的其他示例。

select u.UserId
     , u.UserName
     , c.CaseId
     , c.CaseName    
from Users as u
join Cases as c on u.UserId = c.UserId

union

select u.UserId
     , u.UserName
     , (-1)  as CaseId
     , 'n/a' as CaseName 
from Users as u
where not exists (select 1 from Cases as c where c.UserId = u.userId)
;
相关问题