2011-12-30 83 views
0

如何改進下面的SQL查詢(SQL Server 2008)?我想盡量避免子查詢,和我使用的是他們夫婦產生這樣Subselect查詢改進

StateId  TotalCount  SFRCount  OtherCount 
--------------------------------------------------------- 
AZ    102    50    52 
CA    2931   2750   181 
etc... 

SELECT 
    StateId, 
    COUNT(*) AS TotalCount, 
    (SELECT COUNT(*) AS Expr1 FROM Property AS P2 
     WHERE (PropertyTypeId = 1) AND (StateId = P.StateId)) AS SFRCount, 
    (SELECT COUNT(*) AS Expr1 FROM Property AS P3 
     WHERE (PropertyTypeId <> 1) AND (StateId = P.StateId)) AS OtherCount 
FROM Property AS P 
GROUP BY StateId 
HAVING (COUNT(*) > 99) 
ORDER BY StateId 

回答

10

結果這可能工作一樣,沒有硬數據來檢驗

SELECT 
     StateId, 
     COUNT(*) AS TotalCount, 
     SUM(CASE WHEN PropertyTypeId = 1 THEN 1 ELSE 0 END) as SFRCount, 
     SUM(CASE WHEN PropertyTypeId <> 1 THEN 1 ELSE 0 END) as OtherCount 
    FROM Property AS P 
    GROUP BY StateId 
    HAVING (COUNT(*) > 99) 
    ORDER BY StateId 
+3

你的答案應該有正確的輸出,並且根據我的經驗,'SUM(CASE ...)'與使用內部選擇相比往往是驚人的快。 – ean5533 2011-12-30 15:15:44

+2

太棒了,謝謝!我編輯了你的答案,在「OtherCount」後刪除了一個無關的逗號。 – Scott 2011-12-30 15:24:30

+0

+1,很好的答案 – 2011-12-30 15:40:41

0

你替代方案是使用WHERE條件作爲連接參數的單個自聯接Property。 OtherCount可以通過派生查詢中減去TotalCount - SFRCount得出。

0

另一種方法是使用旋轉功能是這樣的:

SELECT StateID, [1] + [2] AS TotalCount, [1] AS SFRCount, [2] AS OtherCount 
FROM Property 
PIVOT (COUNT(PropertyTypeID) 
     FOR PropertyTypeID IN ([1],[2]) 
     ) AS pvt 
WHERE [1] + [2] > 99 

你需要添加爲每個屬性類型的條目可能是艱鉅的,但它是另一種選擇。斯科特有一個很好的答案。

0

如果PropertyTypeId不爲null,那麼您可以通過單個連接來完成此操作。 Count比Sum快。但是Count plus加入比Sum快。下面的測試用例模仿你的數據。 docSVsys有800,000行,caseID有大約300個唯一值。這個測試用例中的Count plus Join比總和稍快。但是,如果我刪除(nolock),那麼總和大約快1/4。你需要測試你的數據。

select GETDATE() 
    go; 
    select caseID, COUNT(*) as Ttl, 
     SUM(CASE WHEN mimeType = 'message/rfc822' THEN 1 ELSE 0 END) as SFRCount, 
     SUM(CASE WHEN mimeType <> 'message/rfc822' THEN 1 ELSE 0 END) as OtherCount, 
     COUNT(*) - SUM(CASE WHEN mimeType = 'message/rfc822' THEN 1 ELSE 0 END) as OtherCount2 
    from docSVsys with (nolock) 
    group by caseID 
    having COUNT(*) > 1000 
    select GETDATE() 
    go; 
    select docSVsys.caseID, COUNT(*) as Ttl 
    , COUNT(primaryCount.sID) as priCount 
    , COUNT(*) - COUNT(primaryCount.sID) as otherCount 
    from docSVsys with (nolock) 
    left outer join docSVsys as primaryCount with (nolock) 
     on primaryCount.sID = docSVsys.sID 
     and primaryCount.mimeType = 'message/rfc822' 
    group by docSVsys.caseID 
    having COUNT(*) > 1000 
    select GETDATE() 
    go;