有条件的左连接

Posted

技术标签:

【中文标题】有条件的左连接【英文标题】:Left join with condition 【发布时间】:2012-02-27 23:31:02 【问题描述】:

假设我有这些表

create table bug (
    id int primary key, 
    name varchar(20)
)
create table blocking (
    pk int primary key,
    id int, 
    name varchar(20)
)

insert into bug values (1, 'bad name')
insert into bug values (2, 'bad condition')
insert into bug values (3, 'about box')
insert into blocking values (0, 1, 'qa bug')
insert into blocking values (1, 1, 'doc bug')
insert into blocking values (2, 2, 'doc bug')

我想加入id 列上的表格,结果应该是这样的:

id          name                 blockingName
----------- -------------------- --------------------
1           bad name             qa bug
2           bad condition        NULL
3           about box            NULL

这意味着: 我想从#bug 返回所有行 'blockingName' 列中应该只有 'qa bug' 值或 NULL(如果在#blocking 中没有找到匹配的行)


我的幼稚选择是这样的:

select * from #bug t1 
    left join #blocking t2 on t1.id = t2.id
    where t2.name is null or t2.name = 'qa bug'

但这不起作用,因为似乎条件首先应用于#blocking表,然后才加入。

这个问题最简单/典型的解决方案是什么? (我有嵌套选择的解决方案,但我希望有更好的解决方案)

【问题讨论】:

首选mysql,但T-SQL也可以。 你想达到什么目的?是所有没有阻止程序还是有“qa bug”阻止程序的错误? 首先,您的第 2 行不会返回 NULL,因为它在#blocking 中有匹配的行。其次,您使用的是什么 SQL?您有一个 mysql 标记,但这是无效的 mysql 语法(“#”),除此之外,您的查询在 mysql 中有效(请参阅here)。 PK在这里对我来说并不重要(但添加了一些)。 忘记我关于第 2 行的第一句话;我误会你了。 【参考方案1】:

只需将“qa bug”标准放入连接中:

select t1.*, t2.name from #bug t1 
left join #blocking t2 on t1.id = t2.id AND t2.name = 'qa bug'

【讨论】:

【参考方案2】:

正确的选择是:

create table bug (
id int primary key, 
name varchar(20)
)
insert into bug values (1, 'bad name')
insert into bug values (2, 'bad condition')
insert into bug values (3, 'about box')

CREATE TABLE blocking
(
pk int IDENTITY(1,1)PRIMARY KEY ,
id int, 
name varchar(20)
)
insert into blocking values (1, 'qa bug')
insert into blocking values (1, 'doc bug')
insert into blocking values (2, 'doc bug')


select 
t1.id, t1.name,
(select  b.name from blocking b where b.id=t1.id and b.name='qa bug')
from bug t1 

【讨论】:

【参考方案3】:

您似乎只想从#blocking 中选择一行并将其加入#bug。我会这样做:

select t1.id, t1.name, t2.name as `blockingName` 
from `#bug` t1
left join (select * from `#blocking` where name = "qa bug") t2
on t1.id = t2.id

【讨论】:

【参考方案4】:
select * 
from #bug t1 
left join #blocking t2 on t1.id = t2.id and t2.name = 'qa bug'

【讨论】:

【参考方案5】:

确保内部查询只返回一行。 如果返回多个,您可能需要在其上添加前 1。

select 
t1.id, t1.name,
(select  b.name from #blocking b where b.id=t1.id and b.name='qa bug')
from #bug t1 

【讨论】:

【参考方案6】:

这是一个演示:http://sqlfiddle.com/#!2/414e6/1

select
  bug.id,
  bug.name,
  blocking.name as blockingType
from
  bug
    left outer join blocking on
      bug.id = blocking.id AND
      blocking.name = 'qa bug'
order by
  bug.id

通过在左外连接下添加“blocking.name”子句,而不是添加到 where,您表明它也应该被视为“外连接”,或者是可选的。作为 where 子句的一部分,它被认为是必需的(这就是过滤掉空值的原因)。

顺便说一句 - sqlfiddle.com 是我的网站。

【讨论】:

以上是关于有条件的左连接的主要内容,如果未能解决你的问题,请参考以下文章

包括与条件的左连接 has_many 关联

如何在 EF / EF Core 中的第二个表上实现具有某些条件的左连接?

带有附加左表过滤器的左连接性能

左外连接与右外连接区别?

LINQ:具有多个条件的左外连接

日期字段上的左连接 + Where 子句