2011-10-07 92 views
0

我有這樣的查詢。它從表用戶返回TableA和UserName中的ColA和ColB。然後它將TableB中的幾個字段顯示爲結果的附加列。它的工作原理,但有沒有比使用這些多個LEFT JOINS更好的方法?T-SQL刪除多個LEFT JOIN

SELECT a.COlA, a.ColB, u.UserName, 
b1.Value, 
b2.Value, 
b3.Value, 
b4.Value, 

FROM TableA a JOIN Users u ON a.UserId = u.UserId 
    LEFT JOIN TableB b1 ON a.EventId = b1.EventId AND b1.Code = 5 
    LEFT JOIN TableB b2 ON a.EventId = b2.EventId AND b2.Code = 15 
    LEFT JOIN TableB b3 ON a.EventId = b3.EventId AND b3.Code = 18 
    LEFT JOIN TableB b4 ON a.EventId = b4.EventId AND b4.Code = 40 

WHERE (a.UserId = 3) ORDER BY u.UserName ASC 

表B的樣子:

Id | EventId | Code | Value 
---------------------------- 
1 | 1 | 5 | textA 
2 | 1 | 15 | textB 
3 | 1 | 18 | textC 

有時代碼丟失,但每個事件有沒有重複的代碼(所以每個LEFT JOIN是在同一個結果記錄只是一個細胞)。

+0

是否行得通?它是否快得可以接受?如果是和是,爲什麼要改變它? –

+0

多個左連接有什麼問題?如果你的查詢在可接受的時間內返回正確的結果,那麼就把它放在一邊,否則你花時間在沒有價值的東西上 – Pondlife

+0

它看起來有點'哈克' ,尤其是如果我們使用了大量的這些LEFT JOINs,我希望有一種機制可以替代它們。 – yosh

回答

1

我不明白爲什麼要改變的東西是工作,但這裏的另一種方式(它的LEFT連接,而是以不同的方式):

SELECT a.COlA, a.ColB, u.UserName, 
    (SELECT b.Value FROM TableB b WHERE a.EventId = b.EventId AND b.Code = 5), 
    (SELECT b.Value FROM TableB b WHERE a.EventId = b.EventId AND b.Code = 15), 
    (SELECT b.Value FROM TableB b WHERE a.EventId = b.EventId AND b.Code = 18), 
    (SELECT b.Value FROM TableB b WHERE a.EventId = b.EventId AND b.Code = 40) 

FROM TableA a JOIN Users u ON a.UserId = u.UserId 

WHERE (a.UserId = 3) 

ORDER BY u.UserName ASC 
+0

也許所有那些左連接都很慢?我沒有測試,但認爲是一個左連接,有些測試可能會 – Johan

+0

如果'(EventId,Code')上有一個(唯一的)索引,我認爲任何變化都不會在速度上產生太大的變化,但它取決於數據分佈。如果一個事件有幾十或幾百個代碼,你的'GROUP BY'可能比'LEFT JOIN'解決方案慢。 –

+0

對於很多用戶我的意思是,這裏的WHERE(a.UserId = 3)''情況會限制搜索的所有變化不會有任何區別。 –

1

如果您對每EventID和(Code=5Code=15Code=18Code=40)只有一個TableB行,那麼你可以測試這個查詢:

;WITH SourceCTE 
AS 
(
    SELECT a.COlA, a.ColB, u.UserName, b.Code, b.Value 
    FROM TableA a JOIN Users u ON a.UserId = u.UserId 
    INNER /*or LEFT OUTER*/ JOIN TableB b ON a.EventId = b1.EventId AND b.Code IN (5,15,18,40) 
    WHERE (a.UserId = 3) ORDER BY u.UserName ASC 
) 
SELECT pvt.CodA, pvt.ColB, pvt.UserName 
    ,pvt.[5] AS b1Value 
    ,pvt.[15] AS b2Value 
    ,pvt.[18] AS b3Value 
    ,pvt.[40] AS b4Value 
FROM SourceCTE src 
PIVOT (MAX(src.Value) FOR src.Code IN ([5],[15],[18],[40])) pvt; 

注意:如果你有SQL Server 2008您可以創建一個獨特的過濾EventID索引,包括Value有一個過濾器的字段:WHERE Code IN (5,15,18,40)

1
SELECT 
    a.COlA, a.ColB, u.UserName 
    ,MAX(CASE WHEN b.Value = 5 THEN b.value ELSE 0 END) AS V5 
    ,MAX(CASE WHEN b.Value = 15 THEN b.value ELSE 0 END) AS V15 
    ,MAX(CASE WHEN b.Value = 18 THEN b.value ELSE 0 END) AS V18 
    ,MAX(CASE WHEN b.Value = 40 THEN b.value ELSE 0 END) AS V45 
    ,COUNT(CASE WHEN b.Value not IN (5,15,18,40) THEN 1 ELSE NULL END) AS CountVOther 
FROM TableA a 
INNER JOIN Users u ON a.UserId = u.UserId 
LEFT JOIN TableB b ON (a.EventId = b.EventId) 
WHERE (a.UserId = 3) 
GROUP BY a.colA, a.colB, u.Username 
ORDER BY u.UserName ASC