子选择查询改进

时间:2011-12-30 15:09:40

标签: sql sql-server tsql

如何改进下面的SQL查询(SQL Server 2008)?我想尝试避免子选择,我正在使用它们中的一些产生这样的结果

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

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

您的替代选择是Property使用WHERE条件作为加入参数的单个自加入。可以通过在派生查询中减去TotalCount - SFRCount来派生OtherCount。

答案 2 :(得分:0)

另一种选择是使用像这样的PIVOT函数:

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

您需要为每种属性类型添加一个可能令人生畏的条目,但这是另一种选择。斯科特有一个很好的答案。

答案 3 :(得分:0)

如果PropertyTypeId不为null,那么您可以使用单个连接执行此操作。计数比总和快。但是Count加入比Sum更快。下面的测试用例模仿您的数据。 docSVsys有800,000行,caseID有大约300个唯一值。此测试用例中的Count加入稍微快于Sum。但是如果我删除with(nolock)那么Sum大约快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;