需要 3 个表的 SQL 外连接帮助

Kar*_*arl 0 oracle join

见下面的例子。ID_1ID_A用于主键table_1table_3分别。Table_2,主键是ID_1ID_A。由于业务规则,ID_A连接到一个且只有一个ID_1via table_2

我需要一个查询将返回所有行table_1其中,value_1 = 11并加入到的是,我需要行从table_3有一个value_a = 'a',如果它加入到行中table_1,有一个value_1 = 11

请参阅所需的结果。注意没有行

|1 | a |
Run Code Online (Sandbox Code Playgroud)

在结果集中因为value_afor id_a = 'b';

我试过左外连接,但ID_1都返回了。我也试过 CTE,无济于事。这是一个 SQL,我试过了。

Select ID_1, Value_1, ID_A, VALUE_A
   From TABLE_1 t1
   Join TABLE_2 t2 on t1.ID_1 = t2.ID_1
   Left Outer Join TABLE_3 t3 on t2.ID_A = t3.ID_A;
Run Code Online (Sandbox Code Playgroud)

我也试过使用一个临时表,它只包含TABLE_1我需要的结果,但使用临时表的左外连接仍然返回上述行。

DB 是 Oracle,但我更喜欢标准解决方案。此外,性能也是一个考虑因素,因为它TABLE_1有超过 2 亿行并且TABLE_3大约是它的 4 倍。

表格1

| ID_1 | Value_1  |
-------------------
| 1    | 11       |
| 2    | 12       |
| 3    | 11       |
| 4    | 13       |
Run Code Online (Sandbox Code Playgroud)

TABLE_2

| ID_1 | ID_A  |
----------------
| 1    | a     |
| 1    | b     |
| 3    | c     |
| 4    | d     |
Run Code Online (Sandbox Code Playgroud)

表3

| ID_A | Value_A |
------------------
| a    | b       |
| b    | a       |
| c    | e       |
| d    | a       |
Run Code Online (Sandbox Code Playgroud)

结果要求

| ID_1 | ID_A    |  Value_1  | Value_A |
----------------------------------------
| 1    | b       |    11     |    a    |
| 3    | <NULL>  |    11     | <NULL>  |
Run Code Online (Sandbox Code Playgroud)

And*_*y M 7

首先,加入TABLE_2TABLE_3使用内部联接并另外过滤Value_A = 'a'

SELECT
  t2.ID_1,
  t3.ID_A,
  t3.Value_A
FROM
  TABLE_2 t2
  INNER JOIN TABLE_3 t3 ON t2.ID_A = t3.ID_A
WHERE
  t3.Value_A = 'a'
Run Code Online (Sandbox Code Playgroud)

这将为您提供以下结果集:

ID_1  ID_A  Value_A
----  ----  -------
1     b     a
4     d     a
Run Code Online (Sandbox Code Playgroud)

现在使用上面的作为派生表并连接它,这次使用外部连接到TABLE_1,另外过滤结果Value_1 = 11

SELECT
  t1 .ID_1,
  t23.ID_A,
  t1 .Value_1,
  t23.Value_A
FROM
  TABLE_1 t1
  LEFT JOIN
  (
    SELECT
      t2.ID_1,
      t3.ID_A,
      t3.Value_A
    FROM
      TABLE_2 t2
      INNER JOIN TABLE_3 t3 ON t2.ID_A = t3.ID_A
    WHERE
      t3.Value_A = 'a'
  ) t23 ON t1.ID_1 = t23.ID_1
WHERE
  t1.Value_1 = 11
;
Run Code Online (Sandbox Code Playgroud)

会给你你想要的输出

ID_1  ID_A  Value_1  Value_A
----  ----  -------  -------
1     b     11       a
3     NULL  11       NULL
Run Code Online (Sandbox Code Playgroud)

但是,嵌套查询并不是解决问题的唯一方法——您还可以使用嵌套连接,它更简洁:

SELECT
  t1.ID_1,
  t3.ID_A,
  t1.Value_1,
  t3.Value_A
FROM
  TABLE_1 t1
  LEFT JOIN
    TABLE_2 t2
    INNER JOIN TABLE_3 t3 ON t2.ID_A = t3.ID_A AND t3.Value_A = 'a'
  ON t1.ID_1 = t2.ID_1
WHERE
  t1.Value_1 = 11
;
Run Code Online (Sandbox Code Playgroud)

最后一个查询实现与前一个查询完全相同的逻辑:首先,表TABLE_2TABLE_3连接并过滤结果,然后连接到TABLE_1并再次过滤最终集合。有些人还在嵌套连接周围添加括号:

FROM
  TABLE_1 t1
  LEFT JOIN
  (
    TABLE_2 t2
    INNER JOIN TABLE_3 t3 ON t2.ID_A = t3.ID_A AND t3.Value_A = 'a'
  )
  ON t1.ID_1 = t2.ID_1
Run Code Online (Sandbox Code Playgroud)

为了更清楚地(可能对他们自己和未来的维护者)嵌套连接在逻辑上发生在外层连接之前,尽管没有它们语法就足够明确了。

尽管如此,许多人发现即使使用方括号也很困惑,如果您发现自己也在为它苦苦挣扎,那么还有另一种选择 - 右外连接

SELECT
  t1.ID_1,
  t3.ID_A,
  t1.Value_1,
  t3.Value_A
FROM
  TABLE_2 t2
  INNER JOIN TABLE_3 t3 ON t2.ID_A = t3.ID_A AND t3.Value_A = 'a'
  RIGHT JOIN TABLE_1 t1 ON t1.ID_1 = t2.ID_1
WHERE
  t1.Value_1 = 11
;
Run Code Online (Sandbox Code Playgroud)

再次,事件的逻辑顺序指定由FROM子句重复派生表溶液是:之间的联接TABLE_2TABLE_3,过滤,随后是与加入TABLE_1。不同的语法不会改变结果,产生的结果仍然符合您的要求。