3

我有一个简单的表格,例如:

create table #test(x int, y int)
insert into #test values(null, 1)
insert into #test values(1, 1)
insert into #test values(1, 2)
insert into #test values(2, 2)
insert into #test values(3, 2)

我需要通过分组得到总和,但如果组有一个空值,那么得到空值而不是总和。我可以通过两个查询来做到这一点:

1) select y, case when AVG(x)<>SUM(x)/COUNT(*) then null else SUM(x) end from #test
group by y
2) select y, CASE WHEN EXISTS(select * from #test innerTest where innerTest.y=outerTest.y and x is null) then null else sum(x) end 
from #test outerTest group by y

哪个查询的性能更好?还有其他解决方案吗?

4

2 回答 2

7

你可以检查组是否有这样的空值:

select
    y,
    case when count(x) <> count(*) then null else sum(x) end
from test
group by y

sql fiddle demo

我有 99.99% 的把握,这个比带有子查询的运行得更快。

于 2013-10-24T19:15:53.263 回答
1

第一个选项将运行得更快。第 2 个示例中的 CASE WHEN EXISTS 将需要第一个示例中不需要的额外表扫描。如果您使用的是 SQL Server,您可以在查询计划中看到这一点。

如果您使用的是 SQL Server,以下是执行上述语句并在结果中显示执行计划的 TSQL 代码:

CREATE TABLE #test ( x INT, y INT )
INSERT  INTO #test VALUES  ( NULL, 1 )
INSERT  INTO #test VALUES  ( 1, 1 )
INSERT  INTO #test VALUES  ( 1, 2 )
INSERT  INTO #test VALUES  ( 2, 2 )
INSERT  INTO #test VALUES  ( 3, 2 )
GO

SET STATISTICS PROFILE  ON
GO

SELECT  y ,
        sumG = CASE WHEN AVG(x) <> SUM(x) / COUNT(*) THEN NULL
                    ELSE SUM(x)
               END
FROM    #test
GROUP BY y
ORDER BY y ,
        SUM(X) DESC

SELECT  y ,
        sumG = CASE WHEN EXISTS ( SELECT    *
                                  FROM      #test innerTest
                                  WHERE     innerTest.y = outerTest.y
                                            AND x IS NULL ) THEN NULL
                    ELSE SUM(x)
               END
FROM    #test outerTest
GROUP BY y
ORDER BY y ,
        SUM(X) DESC
GO

SET STATISTICS PROFILE  OFF
GO

DROP TABLE #test;
GO

如果您正在使用另一个数据库引擎,我不知道如何向您展示我脑海中的执行计划,但他们中的大多数人都有办法这样做。

注意:我不知道有一种更快的方法来做到这一点,但这并不意味着没有。

于 2013-10-24T18:55:38.850 回答