见下面的例子。ID_1和ID_A用于主键table_1和table_3分别。Table_2,主键是ID_1和ID_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)
首先,加入TABLE_2并TABLE_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_2和TABLE_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_2和TABLE_3,过滤,随后是与加入TABLE_1。不同的语法不会改变结果,产生的结果仍然符合您的要求。
| 归档时间: |
|
| 查看次数: |
18240 次 |
| 最近记录: |