【问题标题】:LEFT JOIN with OR clause without UNION带 OR 子句的 LEFT JOIN 不带 UNION
【发布时间】:2022-08-19 01:48:31
【问题描述】:

我知道这不应该发生在数据库中,但它发生了,我们必须处理它。如果新行不存在,我们需要根据另一个表中的值将它们插入到表中。这很容易(只需执行 LEFT JOIN 并检查第一个表中的 NULL 值)。但是......连接不是很直接,我们需要在 2 个条件下使用 OR 而不是 AND 搜索第一个表。所以基本上如果它在两个属性中的任何一个上找到匹配项,我们认为第一个表中的对应行存在,我们不必插入新的。如果这两个属性中的任何一个都没有匹配项,那么我们将其视为新行。我们可以在 LEFT JOIN 语句中使用 OR 条件,但据我了解,它会进行全表扫描,并且查询需要很长时间才能完成,即使它产生了正确的结果。我们也不能使用 UNION,因为它不会给我们想要的东西。 为简单起见,请考虑以下场景(我们需要将数据插入到 tableA 中)。

If(OBJECT_ID(\'tempdb..#tableA\') Is Not Null) Begin
    Drop Table #tableA End

If(OBJECT_ID(\'tempdb..#tableB\') Is Not Null) Begin
    Drop Table #tableB End

create table #tableA ( email nvarchar(50), id int )

create table #tableB ( email nvarchar(50), id int )


insert into #tableA (email, id) values (\'123@abc.com\', 1), (\'456@abc.com\', 2), (\'789@abc.com\', 3), (\'012@abc.com\', 4)

insert into #tableB (email, id) values (\'234@abc.com\', 1), (\'456@abc.com\', 2), (\'567@abc.com\', 3), (\'012@abc.com\', 4), (\'345@abc.com\', 5)

 --THIS QUERY IS CORRECTLY RETURNING 1 RECORD  
 select B.email, B.id  
 from #tableB B  
 left join #tableA A on A.email = B.email or B.id = A.id  
 where A.id is null

 --THIS QUERY IS INCORRECTLY RETURNING 3 RECORDS SINCE THERE ARE ALREADY RECORDS WITH ID\'s 1 & 3 in tableA though the email addresses of these records don\'t match  
select B.email, B.id  
from #tableB B  
left join #tableA A on A.email = B.email  
where A.id is null  
union 
select B.email, B.id  
from #tableB B  
left join #tableA A on B.id = A.id  
where A.id is null


If(OBJECT_ID(\'tempdb..#tableA\') Is Not Null) Begin
    Drop Table #tableA End

If(OBJECT_ID(\'tempdb..#tableB\') Is Not Null) Begin
    Drop Table #tableB End

第一个查询工作正常,只返回 1 条记录,但表大小只有几条记录,它在 1 秒内完成。当 2 个表有数千条记录时,查询可能需要 10 分钟才能完成。第二个查询当然会返回我们不想插入的记录,因为我们认为它们存在。有没有办法优化这个查询,所以它需要一个可接受的时间来完成?

  • 您的查询对我来说是正确的。如果您没有获得所需的性能,我认为您只需要考虑添加适当的索引即可。
  • \“当 2 个表有数千个或记录时,查询可能需要 10 分钟才能完成。\”这是假设还是您检查过?数以千计的记录实际上并没有那么多,我不希望这样的查询执行得那么糟糕(尤其是如果存在适当的索引)。也许EXISTS 提供了更好的性能,但你确实需要检查执行计划
  • 是的,我在 JOIN 中使用 OR 对其进行了测试,大约需要 10 分钟。表 A 有超过 50,000 条记录,表 B 有近 20,000 条记录。如果我仅在 1 个条件下从 JOIN 和 JOIN 中删除 OR,则需要几秒钟。不幸的是,我们正在处理 SaaS DB,无法在其中创建索引。

标签: sql sql-server left-join union


【解决方案1】:

您仍然可以像这样使用 UNION:

select email, id  
from #tableB B  
where id is not in (select id from #tableA) 
union 
select email, id  
from #tableB B  
where email is not in (select email from #tableA) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-28
    • 2011-01-30
    • 2017-07-31
    • 2018-07-16
    • 2014-12-16
    • 2015-08-21
    • 1970-01-01
    • 2016-10-24
    相关资源
    最近更新 更多