[英]Left Outer join with same table as part of the outer join
我想知道如何通过编写外部联接查询来获得所需的输出(如下所述),其中我正在外部联接的表是语句中其他联接条件的一部分
给定以下数据结构,其中-表A是包含一些任意对象的主表-表A被A引用,其中A.TYPE_ID = B.ID-表C定义表A中对象之间的关系,其中C.SOURCE_ID引用A.ID和C.TARGET_ID引用A.ID
这是定义架构的方式,我对此无能为力(这是旧系统)
TABLE_A
---------------------------
| ID | TYPE_ID | Name |
|-------------------------|
| 1 | 1 | Name 1 |
| 2 | 2 | Name 2 |
| 3 | 1 | Name 3 |
| 4 | 1 | Name 4 |
| 5 | 3 | Name 5 |
|-------------------------|
TABLE_B
----------------------
| ID | TYPE_NAME |
|--------------------|
| 1 | Type 1 |
| 2 | Type 2 |
| 3 | Type 3 |
| 4 | Type 4 |
|--------------------|
TABLE_C
-------------------------------
| PK | SOURCE_ID | TARGET_ID |
|-----------------------------|
| 11 | 2 | 1 |
| 12 | 2 | 3 |
| 13 | 5 | 1 |
| 13 | 5 | 4 |
-------------------------------
我想得到的是“类型1”的表A中的所有对象,以及它们所关联的对象的名称(否则为null),类型2,即外部联接,以获取类型1的所有对象不管他们是否有关联,但是如果他们有关联,那么我需要对象的名称。 请注意,类型1的对象将始终位于关系中的TARGET中。
上面示例的输出为
-------------------------------
| Target Name | Source Name |
|-----------------------------|
| Name 1 | Name 2 |
| Name 3 | Name 2 |
| Name 4 | (NULL) |
|-----------------------------|
我原来的联接查询(无法使外部联接起作用),这是普通联接,不显示没有关联的对象。
select atrgt.NAME, asrc.NAME
from TABLE_A atrgt
JOIN TABLE_B trgttype on atrgt.TYPE_ID = trgttype.ID
and trgttype.TYPE_NAME = 'Type 1'
JOIN TABLE_C assoc on atrgt.ID = assoc.TARGET_ID
JOIN TABLE_A asrc on asrc.ID = assoc.SOURCE_ID
JOIN TABLE_B srctype on asrc.TYPE_ID = srctype.ID
and srctype.TYPE_NAME = 'Type 2'
基本上,在这些情况下,我认为最好的方法是将查询细分为两个普通联接,然后在这些结果集之间进行外部联接。 如果您将SQL视为过程代码,您可能会认为它看起来效率低下,但是查询优化器不一定会独立运行两个子联接。
您没有说您正在使用什么RDBMS。 在Oracle中,我可能会这样写:
with
src_type_2 as (
select c.target_id, a.name
from table_c c
join table_a on a.id = c.source_id
join table_b on b.id = a.type_id
where b.type_name = 'Type 2'
),
all_type_1 as (
select a.id, a.name
from table_a a
join table_b on b.id = a.type_id
where b.type_name = 'Type 1'
)
select tgt.name, src.name
from all_type_1 tgt
left join src_type_2 src on src.target_id = tgt.id
尝试
select atrgt.NAME, baseview.NAME
from TABLE_A atrgt
JOIN TABLE_B trgttype on atrgt.TYPE_ID = trgttype.ID
and trgttype.TYPE_NAME = 'Type 1'
JOIN TABLE_C assoc on atrgt.ID = assoc.TARGET_ID
LEFT JOIN (
TABLE_A asrc on asrc.ID = assoc.SOURCE_ID
JOIN TABLE_B srctype on asrc.TYPE_ID = srctype.ID
and srctype.TYPE_NAME = 'Type 2'
) as baseview
我认为这应该工作:
SELECT
TGT.NAME, SRC_TYPE.TYPE_NAME
FROM TABLE_A TGT
JOIN TABLE_B TGT_TYPE ON TGT.TYPE_ID = TGT_TYPE.ID
LEFT JOIN TABLE_C REL ON TGT.ID = REL.TARGET_ID
LEFT JOIN TABLE_A SRC ON REL.SOURCE_ID = SRC.ID
LEFT JOIN TABLE_B SRC_TYPE ON SRC_TYPE.ID = SRC.TYPE_ID
WHERE TGT_TYPE.TYPE_NAME = 'Type 1' AND COALESCE(SRC_TYPE.TYPE_NAME, 'Type 2') = 'Type 2'
如果使用的是Oracle,则可以用NVL(SRC_TYPE.TYPE_NAME, 'Type 2')
替换COALESCE
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.