如果多个条件之一为真,我如何执行 JOIN?
Posted
技术标签:
【中文标题】如果多个条件之一为真,我如何执行 JOIN?【英文标题】:How do I perform a JOIN if one of multiple conditions is true? 【发布时间】:2014-12-29 21:55:39 【问题描述】:我的最终目标...SELECT
来自qry1
的所有字段位于家庭电话、手机或工作电话与tbl2
匹配的行上
这是我当前“失败”的 SQL 语法。失败是指它在 10-15 分钟后尚未完成执行,而个人加入每个(独立)运行一两分钟。
SELECT qry1.*
FROM qry1 INNER JOIN tbl2
ON ((qry1.CellPhone = tbl2.CellPhone)
OR (qry1.HomePhone = tbl2.HomePhone)
OR (qry1.WorkPhone = tbl2.WorkPhone));
问题: 我的 SQL 语法有错误吗? 有没有更好的方法来完成我的任务? 对我来说,简单地独立运行 3 个(家庭、工作、单元)JOIN 查询,将它们联合起来,然后在必要时进行重复数据删除是否更有意义?
【问题讨论】:
您的 SQL 语法没有错误;如果有,查询将不会运行。桌子大概有多大?每行有多少行,以及典型的行大小。结果集中大概有多少行?这主要是出于好奇——但每个单独的查询需要 1-2 分钟,这表明表必须非常大。 在 Excel(xlsx 格式)中,馈送 qry1 的较大表格为 80 MB,tbl2 为 50 MB。 tbl2 非常宽。 【参考方案1】:如果单个连接工作得很快,那么复合 OR 条件可能会很慢,因为它不能使用单个索引,而单个条件可以对三个连接条件使用单个索引。因为它不能使用一个索引,它很可能是在进行非索引顺序表扫描。 (您应该研究查询计划,以便了解优化器实际在做什么。)
鉴于各个查询的运行速度相当快,因此,您应该使用 UNION 获得更好的性能(除非您的 DBMS 中的优化器存在盲点):
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON qry1.CellPhone = tbl2.CellPhone
UNION
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON qry1.HomePhone = tbl2.HomePhone
UNION
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON qry1.WorkPhone = tbl2.WorkPhone
这应该与 3 个单独的查询一样快地为您提供结果。它不会那么快,因为 UNION 确实进行了重复消除(当然,单个查询不会)。您可以使用 UNION ALL,但如果两个表中有很多行,其中 2 或 3 对字段匹配,则可能会导致结果中出现大量重复。
【讨论】:
我还想补充一点,您使用UNION
进行重复消除正是我所需要的。【参考方案2】:
or
对于 SQL 优化器来说可能相当困难。我会建议 3 个索引和以下查询:
SELECT qry1.*
FROM qry1
WHERE EXISTS (SELECT 1 FROM tbl2 WHERE qry1.CellPhone = tbl2.CellPhone) OR
EXISTS (SELECT 1 FROM tbl2 WHERE qry1.HomePhone = tbl2.HomePhone) OR
EXISTS (SELECT 1 FROM tbl2 WHERE qry1.WorkPhone = tbl2.WorkPhone);
三个索引分别是tbl2(CellPhone)
、tbl2(HomePhone)
和tbl2(WorkPhone)
。
【讨论】:
我认为SELECT NULL ...
比其他虚拟SELECT
-s 更轻。过去我使用SELECT *
表示EXISTS 子查询,但后来看到了一些NULL
的示例。不确定我的方式是否更好......
这段代码很慢,因为我没有创建正确的索引。我的错。
@i486:任何半途而废的查询优化器都会忽略 EXISTS 子查询中的选择列表;不管你写的是*
、1
、NULL
,还是别的什么。
@i486 。 . .为了进一步说明 Jonathan 的观点,一些 SQL 引擎甚至会接受像 1/0
这样的东西作为被选择的东西。【参考方案3】:
如果这本质上是一个自联接,其中相同的人同时存在于 tbl1 和 qry1 中,那么您可能不会对人们匹配自己的位置以及结果的重复排列感兴趣。我的意思是,自我加入通常有两条记录,其中 Bob 和 Jane 具有相同的电话号码,因此您的结果已加入记录:
Bob, Jane
Jane, Bob
Jane, Jane
Bob, Bob
在这些人中,您可能只需要Bob, Jane
,因为它告诉您这两个人有一个匹配的电话号码。 如果您有一些唯一 ID,则添加 where qry1.SSN < tbl2.SNN
将消除其中许多重复项并减少您的结果集。此列最好有一个索引。
【讨论】:
在这种特殊情况下,您的回答/评论并不真正适用,但我知道我将来会遇到与此非常相似的事情。谢谢!【参考方案4】:以下类似于https://***.com/a/27696729/4350148,但使用了不相交的联合。可能效率更高
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON qry1.CellPhone = tbl2.CellPhone
UNION distinct
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON
qry1.CellPhone != tbl2.CellPhone
and qry1.HomePhone = tbl2.HomePhone
UNION distinct
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON
qry1.CellPhone != tbl2.CellPhone
and qry1.HomePhone != tbl2.HomePhone
and qry1.WorkPhone = tbl2.WorkPhone
【讨论】:
以上是关于如果多个条件之一为真,我如何执行 JOIN?的主要内容,如果未能解决你的问题,请参考以下文章
if() if() else else if() else怎么运用,请高手详细的解说一下,一定采纳!