2016-11-30 77 views
2

代碼:T-SQL加入NULL和NOT NULL記錄

CREATE TABLE [dbo].[T1] ([ID1] INT NOT NULL, [ID2] INT NOT NULL); 
CREATE TABLE [dbo].[T2] ([ID1] INT NOT NULL, [ID2] INT NULL, [VAL] INT NOT NULL); 

INSERT INTO [dbo].[T1] ([ID1], [ID2]) 
VALUES (1, 1) 
     ,(1, 2) 
     ,(1, 3) 
     ,(1, 4) 
     ,(1, 5) 
     ,(2, 1); 

INSERT INTO [dbo].[T2] ([ID1], [ID2], [VAL]) 
VALUES (1, NULL, 25000) 
     ,(1, 2, 30000) 
     ,(2, NULL, 30000); 

目標:

T1具有ID1和ID2映射的完整列表。
T2是一個ID1/ID2映射到Val的外部表。

最終目標是當T2.ID2 = NULL時「交叉連接」T1和T2(ID1/ID2),但在T2.ID2具有NOT NULL值時跳過該T1.ID2的輸出,並保持VAL T2代表NOT-NULL T2.ID2s。表演必須快!

所需的輸出:

ID1 ID2 VAL 
1 1 25000 
1 2 30000 -- T1.ID2 = 2 takes the priority 
1 3 25000 
1 4 25000 
1 5 25000 
2 1 30000 

我嘗試:

SELECT [T2].[ID1] 
     , [T1].[ID2] 
     , [T2].[VAL] 
FROM [dbo].[T1] [T1] 
JOIN [dbo].[T2] [T2] 
ON  [T1].[ID1] = [T2].[ID1] 
WHERE [T2].[ID2] IS NULL 
     OR [T1].[ID2] IN (SELECT [T3].[ID2] 
          FROM  [dbo].[T2] [T3] 
          WHERE  [T2].[ID1] = [T3].[ID1] 
            AND [T2].[ID2] = [T3].[ID2]) 
--ORDER BY [T2].[ID1] 
--  , [T1].[ID2] 
--  , [T2].[VAL]; 

電流輸出:

ID1 ID2 VAL 
1 1 25000 
1 2 25000 
1 3 25000 
1 4 25000 
1 5 25000 
1 2 30000 
2 1 30000 

DROP TABLE [dbo].[T1]; 
DROP TABLE [dbo].[T2]; 

回答

2

您的查找表中的默認值。您可以使用left joincoalesce()接近這個:

select t1.id1, t1.id2, 
     coalesce(t2.val, t2default.val) as val 
from t1 left join 
    t2 
    on t1.id1 = t2.id1 and t1.id2 = t2.id2 left join 
    t2 t2default 
    on t1.id1 = t2default.id1 and t2default.id2 is null; 

假設你有在加入使用的ID列正確的索引,性能應該是非常好的。

如果你關心性能,另一種方法可能是值得一試:

select t1.id1, t1.id2, t2.val 
from t1 outer apply 
    (select top 1 t2.* 
     from t2 
     where t2.id1 = t1.id and (t2.id2 is null or t2.id2 = t1.id2) 
     order by (case when t2.id2 = t1.id2 then 1 else 2 end) 
    ) t2; 

這似乎更復雜,我,但有時apply具有令人驚訝的性能好等特點。

+0

謝謝戈登,這個按預期工作。只是好奇,除非它是一個小小的疏忽,爲什麼你沒有在第一個查詢中合併ID2(即合併(t2.id2,t1.id2)爲id2)?順便說一句,令人驚訝的是,第一個解決方案給出了比上述數據更好的執行計劃。將嘗試使用真實/較大表格的邏輯並進行比較。再次感謝。 – 007

+0

@ 007。 。 。這是一個錯字。它應該是't1.id2'。 –