【问题标题】:Why does FULL JOIN order make a difference in these queries?为什么 FULL JOIN 顺序在这些查询中有所不同?
【发布时间】:2017-07-19 16:40:49
【问题描述】:

我正在使用 PostgreSQL。我在这里读到的所有内容都表明,在仅对单个列使用完全连接的查询中,连接的表的顺序基本上无关紧要。

我的直觉说这也应该适用于多列,只要每个公共列都尽可能地列在查询中(即,只要两个连接表都有共同的列)。但不是,我正试图找出原因。

简化为三个表 a、b 和 c。

Columns in table a: id, name_a
Columns in table b: id, id_x
Columns in table c: id, id_x

这个查询:

SELECT *
FROM a
    FULL JOIN b USING(id)
    FULL JOIN c USING(id, id_x);

返回与此不同的行数:

SELECT *
FROM a
    FULL JOIN c USING(id)
    FULL JOIN b USING(id, id_x);

我想要/期望的很难说清楚,但基本上,我想要一个“完整的”完全合并。除非不可避免,否则我不希望任何地方出现空字段。

例如,每当有一个非空 id 时,我希望相应的名称列始终具有 name_a 并且不为空。相反,其中一个示例查询返回半冗余结果,其中一行具有 name_a 但没有 id,另一行具有 id 但没有 name_a,而不是单个合并行。

当连接以其他顺序列出时,我确实得到了想要的结果(但我不确定可能会出现什么其他问题,因为未来的数据是未知的)。

【问题讨论】:

  • 您是否期望输入表中可能存在 NULL?您的某些期望是否取决于超级键上的 FULL JOIN(UNIQUE NOT NULL)?表或连接是否有任何其他限制/约束?就输入而言,您期望/预期的结果究竟是什么?请给出示例输入、查询以及预期/期望和实际输出。 PS我怀疑没有这样的连接链是你想要的结果的查询。我怀疑您需要某些工会,并且 OR 在您的规范中起着重要作用。尝试描述并举例说明您想要 2 个然后 3 个表的内容。
  • 您仍然不清楚您在 GordonLinoff 的回答中写的 cmets 中想要什么。此外,“如果有多行...”正如我在对您的问题的评论中假设的那样,您的情况涉及某些假设但您没有给出它们。事情比你想象的要复杂。如果您想回答您的问题,无论它是什么,请阅读并在minimal reproducible example 上采取行动,然后阅读并根据我的评论采取行动。至少,给出输入和预期输出的例子。另外, cmets 不是为了澄清,请编辑您的问题。另外,请参阅我的答案。
  • 这里是如何“表达”:请 (1) 给出 PK、UNIQUE、NOT NULL、FK 以及任何其他限制您的表一次可以容纳的内容(无论是否声明)&( 2)完成这句话(假设“∈”就像SQL“in”但匹配相同值或两者都为null的列):我想要具有列(id,id_x,name)的行,其中[(id,id_x)∈(b联合c) and ((id,name) in a or (id) not in (select id from a) and name is null)] or ... 。也许 ... 或 (id) 不在 (select id from (b union c)) 和 (id,name) ∈ a 并且 id_x 为空。

标签: sql postgresql null outer-join associativity


【解决方案1】:

您的查询不同。

首先,您使用单列 idb 执行 full join

在第二个中,您使用两列将full join 转换为b

虽然这两个查询在某些情况下可能返回相同的结果,但没有理由认为结果具有可比性。

【讨论】:

  • 这是有道理的。但我不完全明白的是如何强制最后一张桌子的id 始终与第一张桌子融合在一起,就像与第二张桌子一样。直觉上,当我有 USING 关键字时,这就是我期望 FULL JOIN 工作的方式,因为只返回一个 id 列。
  • @Lenoxus “总是被融合”是什么意思? PS 定义,而不是直觉。
  • 我明白为什么不清楚。我希望结果表的行数尽可能少。所以:没有空值,除非一个值真的无法确定。如果有多行具有相同的 id 和 id_x 值,这一定是因为表 b 和 c 都有具有这些值的行。结果表应反映这些表数据中的每个关系/重叠,但仅此而已。
【解决方案2】:

参数顺序在 OUTER JOIN 中很重要,除了 FULL NATURAL JOIN 是对称的。它们返回 INNER JOIN(ON、USING 或 NATURAL)所做的事情,以及由 NULL 扩展的左侧(LEFT JOIN)、右侧(RIGHT JOIN)或两者(FULL JOIN)表中不匹配的行。

USING 返回 INNER JOIN 行中每个指定列的单个共享值;在 NULL 扩展行中,另一个常见列可以在一个表的版本中具有 NULL,而在另一个表的版本中具有值。

加入订单也很重要。甚至 FULL NATURAL JOIN 也不是关联的,因为对于多个表,每对表(操作数是原始的或连接结果)都可以有一组唯一的公共列,即通常 (A ⟗ B) ⟗ C ≠ A ⟗ (B ⟗ C)。

在许多特殊情况下,某些额外的身份是成立的。例如,使用所有常见列名的 FULL JOIN 和 OUTER JOIN ON 同名列的相等性是对称的。某些情况涉及 CK(候选键)、FK(外键)和其他参数约束。

您的问题并没有明确说明您假设的输入条件或寻求的输出条件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    相关资源
    最近更新 更多