左外连接与同一个表作为外连接的一部分

发布于 2024-12-22 05:54:35 字数 1819 浏览 4 评论 0原文

我想知道如何通过编写外连接查询来获取所需的输出(如下所述) 我外部连接的表是语句中其他连接条件的一部分,

给出以下数据结构,其中 - 表A是包含一些任意对象的主表 - 表 B 由 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'

I was wondering how I could go by writing a the outer join query to get the required outputs (described below)
where the tables I am outer joining are part of the other join conditions in the statement

given the following datastructure where
- Table A is the main table containing some arbitrary objects
- Table B is referenced by A where A.TYPE_ID = B.ID
- Table C defininfs relations between the objects in Table A where C.SOURCE_ID references A.ID and C.TARGET_ID references A.ID

This is how the schema is defined and I can't do anything about it (it's a legacy system)

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         |
-------------------------------

What I would like to get is all the objects in Table A of "Type 1" with the name of the object they are associated to (null otherwise) which are of Type 2,
i.e an outer join to get all the objects of Type 1 regardless if they have an association, but if they do then I need the name of the object.
Note that objects of Type 1 will always been in the TARGET in the relstionship.

The output for the above example would be

-------------------------------
| Target Name | Source Name   |
|-----------------------------|
| Name 1      | Name 2        |
| Name 3      | Name 2        |
| Name 4      | (NULL)        |
|-----------------------------|

My original join query (couldn't get the outer join to work) this is the normal join not showing objects with no associations.

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'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷你仙 2024-12-29 05:54:35

基本上在这些情况下,我认为最好的方法是将查询细分为两个普通联接,然后在这些结果集之间进行外联接。如果您将 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

Basically in these situations I think the best approach is to subdivide the query into two normal joins, then do the outer join between those results sets. If you think of SQL as procedural code, you may think it looks inefficient, but the query optimizer will not necessarily run the two subjoins independently.

You didn't say what RDBMS you are using. In Oracle I would probably write it like this:

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
誰ツ都不明白 2024-12-29 05:54:35

尝试

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

Try

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
花期渐远 2024-12-29 05:54:35

我认为这应该可行:

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,则可以将 COALESCE 替换为 NVL(SRC_TYPE.TYPE_NAME, 'Type 2')

I think this should work:

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'

If you're using Oracle, you could replace the COALESCE with NVL(SRC_TYPE.TYPE_NAME, 'Type 2').

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文