FULL OUTER JOIN 不返回所有表的内容

Posted

技术标签:

【中文标题】FULL OUTER JOIN 不返回所有表的内容【英文标题】:FULL OUTER JOIN is not returning content of all tables 【发布时间】:2021-06-09 20:26:34 【问题描述】:

如下所述,我有 3 张桌子。

表格

BUG

Id | Name | Other information ...
1  | Bug1 | ...
2  | Bug2 | ...
3  | Bug3 | ...
4  | Bug4 | ...
5  | Bug5 | ...

链接

Id  | Test_id | Bug_id
100 | 1000    | 4
101 | 1100    | 2
102 | 1200    | 2
103 | 1200    | 5

测试

Id   | Name | Other information ...
1000 | TC1  | ...
1100 | TC2  | ...
1200 | TC3  | ...
1300 | TC4  | ...
1400 | TC5  | ...
1500 | TC6  | ...

请求

SELECT Bug.Id, Bug.Name, Test.Id, Test.Name
FROM Test FULL OUTER JOIN Link ON Link.Test_id = Test.Id
FULL OUTER JOIN Bug ON Link.Bug_id = Bug.Id
INNER JOIN Test_Detail ON Test_Detail.Test_id = Test.Id
INNER JOIN Release ON Release.Id = Test.Release_id
INNER JOIN Cycle ON Cycle.Release_id = Release.Id

但是,这并没有提供预期的结果......

预期结果

如果有链接,我想获取有关该错误的信息和 测试 如果有没有链接的错误,我想得到 错误信息 如果有没有链接的测试,我想获取有关测试的信息

结果

BugId | BugName | TestId | TestName
1     | Bug1    |
2     | Bug2    | 1100   | TC2
2     | Bug2    | 1200   | TC3
3     | Bug3    |
4     | Bug4    | 1000   | TC1
5     | Bug5    | 1200   | TC2
      |         | 1300   | TC4
      |         | 1400   | TC5
      |         | 1500   | TC6
    

结论

FULL OUTER JOIN 不是要使用的正确连接吗?您能否帮助了解为什么它没有按预期工作?

谢谢

编辑 1

结果基于 Charlieface 的回答。

我得到了错误、测试和链接。但如果它存在,我只需要链接。如果没有链接,我需要测试和错误详细信息。如上文预期结果部分所述。

BugId | BugName | TestId | TestName
      |         | 1100   | TC2
      |         | 1200   | TC3
2     | Bug2    |        | 
2     | Bug2    | 1100   | TC2
2     | Bug2    | 1200   | TC3

编辑 2

完整请求

TESTCYCL 在这篇文章中是TEST

SELECT DISTINCT
B.BG_BUG_ID
, B.BG_STATUS
, B.BG_SUMMARY
, B.BG_USER_TEMPLATE_13
, B.BG_SEVERITY
, B.BG_PRIORITY
, B.BG_USER_TEMPLATE_10
, B.BG_USER_TEMPLATE_08
, R.REL_NAME
, RC2.RCYC_NAME
, B.BG_DETECTION_DATE
, B.BG_RESPONSIBLE
, B.BG_USER_TEMPLATE_03
, B.BG_USER_03
, B.BG_CLOSING_DATE
, B.BG_USER_TEMPLATE_19
, B.BG_USER_TEMPLATE_18
, B.BG_DETECTED_BY
, TC.TC_TESTCYCL_ID
, TC.TC_TEST_ID
, T.TS_NAME
, TC.TC_STATUS
, T.TS_USER_TEMPLATE_05
, CF.CF_ITEM_NAME
, C.CY_CYCLE
, RC1.RCYC_NAME
, TC.TC_USER_TEMPLATE_06
, TC.TC_USER_TEMPLATE_05
, TC.TC_USER_TEMPLATE_08
FROM TESTCYCL AS TC
INNER JOIN RELEASE_CYCLES AS RC1 ON TC.TC_ASSIGN_RCYC = RC1.RCYC_ID
INNER JOIN TEST AS T ON TC.TC_TEST_ID = T.TS_TEST_ID
INNER JOIN CYCLE AS C ON TC.TC_CYCLE_ID = C.CY_CYCLE_ID
INNER JOIN CYCL_FOLD AS CF ON C.CY_FOLDER_ID = CF.CF_ITEM_ID
FULL OUTER JOIN LINK AS L ON L.LN_ENTITY_ID = TC.TC_TESTCYCL_ID
FULL OUTER JOIN BUG AS B
INNER JOIN RELEASE_CYCLES AS RC2 ON B.BG_DETECTED_IN_RCYC = RC2.RCYC_ID
INNER JOIN RELEASES AS R ON B.BG_DETECTED_IN_REL = R.REL_ID
ON L.LN_BUG_ID = B.BG_BUG_ID

【问题讨论】:

什么是内连接,可能会影响它。 @DaleK 呵呵,full join 什么时候做的? 我有 4 个内部连接来从其他表中获取内容,但只链接到 testbug。它应该不会影响testbuglink之间的链接。 这就是的想法。请edit 并添加完整查询 我在请求中添加了INNER JOIN。它仅用于获取有关测试的更多信息。 FULL JOIN ON 返回 INNER JOIN ON 行 UNION ALL 不匹配的由 NULL 扩展的左右表行。作为 OUTER JOIN ON 的一部分,始终知道您想要什么 INNER JOIN ON。在 FULL JOIN ON 之后,需要 right/left/2 [sic] 表的某些列不为 NULL 的 WHERE、HAVING 或 INNER JOIN 删除此类表的列的 NULL 扩展行,即只留下 RIGHT/LEFT/INNER [sic] JOIN ON 行,即“将 FULL JOIN 变为 RIGHT/LEFT/INNER JOIN”。你有那个。 【参考方案1】:

您需要重新排序您的联接。

将与一个表相关的所有inner joins 与该表放在一起。:

SELECT Bug.Id, Bug.Name, Test.Id, Test.Name
FROM Test
INNER JOIN Test_Detail ON Test_Detail.Test_id = Test.Id
INNER JOIN Release ON Release.Id = Test.Release_id
INNER JOIN Cycle ON Cycle.Release_id = Release.Id
FULL OUTER JOIN Link ON Link.Test_id = Test.Id
FULL OUTER JOIN Bug ON Link.Bug_id = Bug.Id

让我们假设你也想在Bug 上加入一些东西。为此,您需要嵌套ON 条件:

SELECT Bug.Id, Bug.Name, Test.Id, Test.Name
FROM Test
INNER JOIN Test_Detail ON Test_Detail.Test_id = Test.Id
INNER JOIN Release ON Release.Id = Test.Release_id
INNER JOIN Cycle ON Cycle.Release_id = Release.Id
FULL OUTER JOIN Link ON Link.Test_id = Test.Id
FULL OUTER JOIN Bug
      INNER JOIN Bug_Detail bd ON bd.Bug_id = Bug.id
  ON Link.Bug_id = Bug.Id

请注意,与流行观点相反,括号() 在这里没有什么区别,尽管它们在视觉上很有用。 ON 子句的顺序很重要:Bug_detail 内连接嵌套在 Bug 的全连接内

【讨论】:

感谢您提供这个非常有趣的答案!但是,如果有链接,request 返回一行错误,一行错误和链接的测试,一行测试。我在帖子中举了一个例子。如果有链接,我就不用拿bug和测试记录了。 我从您的原始编辑中复制了一个错误类型,现在已修复。您是否在使用 任何其他 joinwhere 谓词,因为这应该有效? 我没有使用 where 子句,并且对于您解释了如何为测试和错误执行的连接。然而奇怪的是,对于某些错误,我有一行包含错误详细信息,另一行包含错误和测试详细信息。相同的错误但出现了 2 次(一次没有关联测试,一次有关联测试) 这是不可能的,除非您有其他谓词或连接,或者 bugid 不匹配(可能是尾随空格或其他东西)。从您给出的结果来看,您确实有一个额外的谓词somewhere(可能在查询的其他地方)。请edit 并添加您当前的查询完整 我添加了完整的查询。我看不出你的回答有什么不同(当然是 SELECT)【参考方案2】:

您的内部连接正在将完整的外部连接变成其他东西。重新排列连接并使用括号:

SELECT Bug.Id, Bug.Name, Test.Id, Test.Name
FROM (Test JOIN
      Test_Detail
      ON Test_Detail.Test_id = Test.Id JOIN
      Release
      ON Release.Id = Test.Release_id JOIN
      Cycle
      ON Cycle.Release_id = Release.Id
     ) FULL OUTER JOIN
     Link
     ON Link.Test_id = Test.Id FULL OUTER JOIN
     Bug
     ON Link.Bug_id = Bug.Id;

【讨论】:

括号什么都不做,这是ON子句的顺序 @philipxy 。 . .因为该逻辑可以在FROM 子句中的任何位置。如果它遵循其他表引用,则需要括号(这是我编写查询的原始方式)。谢谢你的慰问。了解FULL JOIN 是应用于它之前的all 内部连接还是仅应用于最近的表也很棘手。结果完全不同,我更喜欢在这些情况下使用括号来非常清楚地表达意图。 我不明白“该逻辑可能在 FROM 子句中的任何位置”。我想您的意思是我所期望的,您使用括号表示最好将封闭的表视为一个单元,以最清晰的查询含义结构,因为人们可能会使用 CTE 和/或可能会使用指示评论所描述的值。但很多时候我们可以做到但我们做不到。 无论如何,我认为问题帖的规范不连贯,整个演示文稿一团糟。 我不明白您的“FULL JOIN 是否适用于所有内部连接”,因为连接总是将所有内容作为左参数。尽管交叉和内连接是可交换的,所以我们可以重新排列它们链中参数的顺序。 (只要 ON 中的列保持在范围内。但是我们有类似的选项来重新排列 ON 连词的位置。)

以上是关于FULL OUTER JOIN 不返回所有表的内容的主要内容,如果未能解决你的问题,请参考以下文章

SQL的JOIN语法解析(inner join, left join, right join, full outer join的区别)

SQL的JOIN语法解析(inner join, left join, right join, full outer join的区别)

Full Outer Join 不包括双方的所有记录

oracle的full outer join如何排除掉空值

如何在 MySQL 中进行 FULL OUTER JOIN?

如何在 MySQL 中进行 FULL OUTER JOIN?