【问题标题】:Left join in SQL Developer yields incomplete master/left tableSQL Developer 中的左连接产生不完整的主/左表
【发布时间】:2018-05-06 09:54:17
【问题描述】:

通常,当对两个表进行左连接时,左表(A)的所有行都被保留,而右表(B)仅在匹配连接条件时才被连接,例如A.ID = B.ID。 这适用于小型测试数据集。

但是,当我尝试将集合 A 与相当大的集合 B 连接时(即 B 中唯一 ID 的数量大约是 A 中唯一 ID 数量的 100 倍),结果数据集仅包含 A 的那些行具有与 B 匹配的 ID,在我的理解中,这是一个正常的(内部)连接。

我通过左连接集合 A 获得所需的结果表,其中仅包含集合 B 中与集合 A 具有匹配 ID 的行,但我不明白为什么简单的左连接不会产生相同的结果。

很遗憾,我无法使用测试数据复制结果。

一般来说,左连接后截断左表有可能的原因吗?

编辑:

A组:

ID  name
X1  AB
X2  XY
X3  VT
X4  ZY
X5  YZ
X6  KJ
X7  HA
X8  BK
X9  LM

B组:

ID  Var1
X1  blue
X11 red
X3  yellow
X4  blue
X12 yellow
X6  red
X7  orange
X7  blue
X8  green
X9  green
X10 blue

这给出了一个截断集 A:

select A.*, B.Var1 from
setA A 
left join setB B
on A.ID = B.ID
where B.Var1 = 'blue';

这给了我想要的:

select A.*, B.Var1 from
setA A 
left join (select * from setB where Var1 = 'blue') B
on A.ID = B.ID;

我现在明白 where 放置在 join 之后过滤连接结果,并且我需要将 joinwhere 视为两个单独的任务(对吗?)。 但是,对我(作为非专家)来说,B.Var1 = 'blue' 过滤连接结果似乎并不自然,尽管它说 B.Var1 而不仅仅是 Var1,我可以更容易理解以引用连接结果。 B. 建议(对我)以某种方式影响连接中使用的左表。

【问题讨论】:

  • Unfortunately, I cannon replicate the result with test data. 我们也不行。
  • @Aki 。 . .毫无疑问,您有一个 where 子句将外连接变为内连接。

标签: sql oracle join left-join


【解决方案1】:

TL/DR使用setA A left join setB B on A.ID = B.ID and B.Var1 = 'blue'

左表 (A) 的所有行都被保留,右表 (B) 仅在匹配连接条件时才被连接,例如A.ID = B.ID"

不清楚你想说什么。

left join on 被定义为返回inner join on 行加上由nulls 扩展的不匹配的左表行。如果不是 A 的所有行都在结果中,那么您在 left join on 之后添加了 where(或 inner join onright join on)。 无论何时你left join on,都清楚你想要什么关联inner join on;这就是决定on的原因。

这是否意味着 [outer] 连接中不允许使用 where 子句?

这(评论)也很奇怪,因为where 永远不会“进入”(外部或内部)连接,它总是在任何连接之后。 (您可以将inner join 视为类似于cross join,将on 视为类似于where,但优先级更高。)

这给了我想要的:

select A.*, B.Var1 from
setA A 
left join (select * from setB where Var1 = 'blue') B
on A.ID = B.ID;

“自然”的措辞也是如此:

select A.*, B.Var1 from
setA A
left join setB B
on A.ID = B.ID
and B.Var1 = 'blue';

但是,对我(作为非专家)来说,这似乎并不自然

inner join on 被定义为返回满足(整个)on 条件的cross join 行。描述这一点的另一种方式是,对于每个输入中的每一对可能的行,都会生成一个组合行,但只有当它满足(整个)on 条件时才会输出。描述这一点的另一种方式是,对于来自每个输入的每一对可能的行,只有当它们满足(整个)on 条件时,它们才会组合成一个输出行。

有些人似乎使用后两种解释中的一种,但有误解。他们认为inner join on 输出的东西cross join 不同,然后由on 过滤。或者他们认为join 只能是on 一个条件,涉及(无论他们的意思是什么)来自两个输入的列——就好像必须提到每个列,以便可以组合并可能输出。但是不可以——on 条件可以是任何东西,并且只针对每个可能的输入行配对进行评估。

CROSS JOIN vs INNER JOIN: CROSS JOIN = (INNER) JOIN = 逗号 (",")
What is the difference between “INNER JOIN” and “OUTER JOIN”?
(请注意那里的许多其他答案中的废话和糟糕的写作。)

B.Var1 = 'blue' 过滤了连接结果,尽管它显示B.Var1 而不仅仅是Var1,我可以更容易地理解它以引用连接结果。 B. 建议(对我)以某种方式影响连接中使用的左表。

这是更不清楚和奇怪的措辞。似乎你有需要放弃的误解。如果您试图强迫自己清楚地 表达引用的陈述以及您期望joins 和on 的工作方式,这可能会有所帮助。 (成为/成为专家的一个必要条件是不能容忍阅读、思考或写作的马虎。)

【讨论】:

  • 首先,我的评论中有一个错字(我说的是内部联接,而我的意思是外部联接),亚历克斯已经指出了这一点。我认为没有必要在您的回答中强调这一点。关于我的问题:我试图用文字而不是代码来解释我的问题,我知道这经常会导致误解。对此感到抱歉。但是,我想我明白什么是左连接,我只是不习惯使用 SQL。我也理解 MWE 的重要性,但有时很难提供。感谢@GordonLinoff,问题可以轻松解决。
  • 嗨。我没有引用你在 WHERE 是因为 INNER,我知道你的意思是 OUTER。 (你现在提到它很奇怪,因为 WHERE 不是“加入”任何一种加入。)(确实很奇怪,在你认为你没有混淆之后才谈到“加入”。)我引用了那个评论,因为,正如我所说,你的预期输出和“WHERE in a join”表明存在基本误解。我写了一个答案,我觉得适当地解决了所涉及的误解。 PS 评论是短暂的,用于要求澄清,问题和答案是永久性的。
  • 谢谢,现在我明白你的意思了。我知道专家们一定很难处理表述不当的问题。你是对的,我真的没有看到“where”子句与连接本身无关,而是“之后”改变了结果。不,我没有使用过时的符号。我会尝试插入 MWE,但实际上我的问题已经被问过好几次了。
  • 我回答您的问题而不是作为重复链接到通用说明重新选择或左连接与右连接或连接与哪里的原因是您似乎有两个我认为的具体误解这个问题有点不同。
【解决方案2】:

从概念上讲,您的查询在技术上很好。您只是忘记了 (+) 运算符。应该是

select A.*, B.Var1 from
setA A 
left join setB B
on A.ID = B.ID
where B.Var1(+) = 'blue';  -- Notice the magic (+) symbol

(+) 符号来自old style Oracle join syntax,可能发音为“如果 B.Var1 存在,则等于蓝色”。否则它将只允许变量具有匹配值的行,这意味着它必须存在。

更现代的写法是:

select    A.*, 
          B.Var1 
from      setA A 
left join setB B  on  A.ID   = B.ID
                  AND B.Var1 = 'blue';  

换句话说,将其从where 中取出,并通过and 继续将其保留为on 条件的一部分。

【讨论】:

  • @Aki 我的回答已经给出了这个正确的inner join on 查询。 (我称它为“自然”。)回复(+):甚至Oracle itself deprecates that (very limited) notation。此外,此处使用错误:它用于通过 , 加入以在 where(“Oracle 推荐”项目符号 2)中使用而没有 join(项目符号 1),并且必须出现在所有 B. 列(项目符号 3 和4)。 (但是--没有minimal reproducible example。)这里无关紧要--on 是为了完整的outer join 通用性而引入的。你只是没有正确使用on
  • @Aki Re “您的查询在技术上概念上很好。”相反,无论这应该是什么意思,请参阅我对问题中的 misconceptions 的回答。 (另见“当心”。)
  • 好吧,我当然不建议对您的系统使用第一个示例。它旨在帮助 OP 遵循推理。第二个例子是正确的写法。
  • @philpxy 这不是废话。 (+) 用于 where 子句,其中行可能不存在于连接的另一侧,这正是 OP 在概念上正在努力解决的问题。但我明白我的回答对没有帮助,因为那不是我的目标。
  • @JohnWu (cc @Aki) 阅读我对此答案的第一条评论。它说明您使用(+) 的代码无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多