2015-11-20 29 views
4

我試圖加入3個表格,其中第三個表格包含對第二個和第一個的引用;我希望這些參考文獻的結果。但是,如果第三個表格引用第一個表格,我不需要第二個表格的結果。加入第三個表格,直接與第一個或通過中介

這很難解釋,所以我已經說明了我以下的例子。

第一個select語句產生6行;我明白爲什麼,但那不是我所追求的。

第二個2給出我以後的結果,但是他們有一個代碼味道。任何人都可以提出一個更好的方法來實現相同的輸出嗎?

參見SQL小提琴:http://sqlfiddle.com/#!3/8029cc/1

--code to setup my example 

    declare @t1 table (id bigint, val nvarchar(10)) 
    declare @t2 table (id bigint, t1Id bigint, val2 nvarchar(10)) 
    declare @t3 table (id bigint, t1Id bigint, t2Id bigint, val3 nvarchar(10)) 

    insert @t1 (id, val) values (1, '1.1') 

    insert @t2 (id, t1Id, val2) 
    values (1, 1, '2.1') 
    ,(2, 1, '2.2') 
    ,(3, 1, '2.3') 

    insert @t3 (id, t1Id, t2Id, val3) 
    values (1, 1, null, 'XXX') 
    , (1, null, 1, '3.1') 
    ,(2, null, 2, '3.2') 
    ,(3, null, 3, '3.3') 

--this produces 6 results; I only want 4 

    select * 
    from @t1 t1 
    left outer join @t2 t2 
     on t2.t1Id = t1.Id 
    left outer join @t3 t3 
     on t3.t2Id = t2.Id 
     or t3.t1Id = t1.id 

--this works, but means repeating myself; which I'd prefer not to do if possible (could use a cte to make that simpler in the real world scenario, but still not ideal) 

    select t1.id, t2.id, t3.id, t1.val, t2.val2, t3.val3 
    from @t1 t1 
    left outer join @t2 t2 
     on t2.t1Id = t1.Id 
    left outer join @t3 t3 
     on t3.t2Id = t2.Id 

    union all 

    select t1.id, null, t3.id, t1.val, null, t3.val3 
    from @t1 t1 
    left outer join @t3 t3 
     on t3.t1Id = t1.id 

--this works too, but feels very hacky 

    select t1.id, t2.id, t3.id, t1.val, t2.val2, t3.val3 
    from @t1 t1 
    left outer join 
    (
     select id, t1id, val2 
     from @t2 

     union all 

     select null, null, null 

    ) t2 
     on coalesce(t2.t1Id,t1.Id) = t1.Id 
    left outer join @t3 t3 
     on t3.t2Id = t2.Id 
     or (t3.t1Id = t1.id and t2.Id is null) 

更新

我只是想另一個解決方案,感覺有點清潔除以上的;儘管我仍然有點不舒服...

--another option; again slightly hacky 

    select id, id2, id3, val, val2, val3 
    from 
    (
     select t1.id 
     , case when t3.t1Id = t1.id then null else t2.id end id2 
     , t3.id id3 
     , t1.val 
     , case when t3.t1Id = t1.id then null else t2.val2 end val2 
     , t3.val3 
     , row_number() over (partition by t1.id order by case when t3.t1Id = t1.id then null else t2.id end, t3.id) x 
     from @t1 t1 
     left outer join @t2 t2 
      on t2.t1Id = t1.Id 
     left outer join @t3 t3 
      on t3.t2Id = t2.Id 
      or t3.t1Id = t1.id 
    ) t 
    where id2 is not null or x = 1 
+0

ps。對於任何人使用上述找到他們的問題的解決方案,我發現,在大多數的現實情況下,上面的第一個工作解決方案(即't1加入t2連接t3'和't1連接t3'的結果之間的'union all'' )是最高效的。 – JohnLBevan

+0

更新:迄今爲止的大多數答案都建議將t3移至FROM。如果我在測試日期添加新的值; 'insert @ t1(id,val)values(1,'1.1'),(8,'8.1')'你會看到這個方法的一個問題。即我們不再有來自t1的每個值。 – JohnLBevan

回答

1

也許我並沒有完全理解您的需求/輸出。

但是,查詢應該有相同的結果

SELECT * 
FROM t3 
LEFT JOIN t2 
    ON t2.id = t3.t2Id 
LEFT JOIN t1 
    ON t3.t1Id = t1.id 
    AND t2.id IS NULL 
1

嘗試此查詢時,會產生相同的輸出結果作爲您的最後一個查詢:

SELECT T.ID, 
     CASE WHEN T3.t2Id IS NULL THEN NULL ELSE T.T2ID END AS T2ID, 
     T3.id AS T3ID, 
     T.VAL, 
     CASE WHEN T3.t2Id IS NULL THEN NULL ELSE T.VAL2 END AS VAL2, 
     T3.VAL3 
FROM (SELECT T1.id, 
      T1.val, 
      T2.Id AS T2ID, 
      T2.val2 
     FROM @t1 AS T1 JOIN @t2 AS T2 
        ON T1.id = T2.t1id 
    ) AS T JOIN @t3 AS T3 
      ON T.T2ID = T3.ID 
ORDER BY T3.VAL3 

test is here

輸出結果

enter image description here

1

很簡單 - 你的錯誤是你的起始表。 從表3開始,並將其與其他人連接 - 然後添加一個where條件。 也就是說

SELECT * FROM @t3 
    LEFT OUTER JOIN @t1 
    ON [@t1].id = [@t3].t1id 
    LEFT OUTER JOIN @t2 
    ON [@t2].id = [@t3].t2id 
    WHERE [@t1].id IS NOT NULL 
    OR ([@t2].id IS NOT NULL AND [@t1].id IS NULL) 
+0

你測試了你的查詢嗎? – Vasily

相關問題