2011-12-20 107 views
1

我想知道如何通過編寫外連接查詢來獲得所需的輸出(如下所述) 其中外連接的表是其他連接條件在語句左外連接與相同的表作爲外連接的一部分

給出的以下數據結構,其中 - 表A是含有一些任意對象 主表 - 表B由A引用其中A.TYPE_ID = B.ID - 表C之間defininfs關係表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中的所有對象是與它們與之相關聯的對象的名稱(否則爲空),它們是類型2, 即外部連接以獲得類型1的所有對象,而不管它們是否具有關聯,但是如果它們這樣做,那麼我需要對象的名稱。 請注意,類型1的對象將始終處於目標中。

對於上面例子中的輸出是

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

您的'正確的'輸出表應該包含名稱1的附加行嗎? – Mikeb 2011-12-20 13:13:47

+0

不,因爲我想要所有的類型1,並且只有它們與類型2相關時才顯示類型2信息。在這種情況下,名稱1與類型2和類型3都關聯,但我對此不感興趣。 – omarello 2011-12-20 13:19:32

回答

5

基本上在這種情況下我認爲最好的辦法是將查詢細分爲兩個正常連接,然後做外的結果集之間的連接。如果您將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 
+0

哇,這看起來很乾淨。我會嘗試它(以前沒有使用'with'子句)。哦,我正在使用Oracle。 – omarello 2011-12-20 13:20:05

0

嘗試

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

我認爲你有一個錯誤。我相信理想的結果應該包括所有「類型1」的對象,不管它們是否是關係的目標。在驅動連接中包含'table_c'將結果限制爲僅作爲某些關係目標的那些對象。 – 2011-12-20 13:07:08

0

我認爲這應該工作:

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