2011-10-07 55 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