Левое внешнее соединение с той же таблицей, что и часть внешнего соединения - PullRequest
1 голос
/ 20 декабря 2011

Мне было интересно, как я мог бы написать письменный запрос на внешнее соединение, чтобы получить необходимые выходные данные (описанные ниже), где таблицы, к которым я выполняю внешнее соединение, являются частью других условий соединения в данной инструкции

следующая структура данных, где - Таблица 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         |
-------------------------------

Что бы я хотел получитьэто все объекты в таблице A типа «1» с именем объекта, с которым они связаны (в противном случае - ноль), которые относятся к типу 2, то есть к внешнему соединению, чтобы получить все объекты типа 1 независимо от того, имеют ли они связь, но если они это сделают, тогда мне нужно название объекта.Обратите внимание, что объекты типа 1 всегда будут в TARGET в relstionship.

Выходные данные для приведенного выше примера будут

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

Ответы [ 3 ]

6 голосов
/ 20 декабря 2011

В основном в этих ситуациях я думаю, что лучший подход - это разделить запрос на два нормальных объединения, а затем выполнить внешнее соединение между этими наборами результатов. Если вы думаете о SQL как о процедурном коде, вы можете подумать, что он выглядит неэффективно, но оптимизатор запросов не обязательно будет запускать эти два подсоединения независимо.

Вы не сказали, какую СУБД вы используете. В 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
0 голосов
/ 20 декабря 2011

Я думаю, что это должно работать:

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').

0 голосов
/ 20 декабря 2011

Попробуйте

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...