1

我查看了其他几个问题,试图找到答案,但我做不到。事情是这样的,我有一张非常大的桌子,可以无限期地增长。当我说BIG时,我的意思是我有大约 1000 万行用于 6 小时数据的查询。我们有几个月的数据,所以你可以看到它有多大。

好吧,证明大小问题是合理的,我想做一个非常简单的查询:按列分组并对另一列的值求和。例如,我想要最大的 10 个总和,以及所有其他不在前 10 位的总和。我知道有办法做到这一点,但我想这样做而不必计算总计表两次。为此,我使用了表变量。我正在使用 SQL SERVER 2012。

DECLARE @sumsTable TABLE(operationName varchar(200), operationAmount int)
DECLARE @topTable TABLE(operationName varchar(200), operationAmount int)
DECLARE @startTime DATETIME
DECLARE @endTime DATETIME
DECLARE @top INTEGER

SET @top = 10
SET @endTime = '03/11/2013'
SET @startTime = '03/10/2013'

--grouping by operationName and summing occurences
INSERT INTO @sumsTable
SELECT operationName, COUNT(*) AS operationAmount
FROM [f6f87bf0-33ab-4882-8674-2cb31e5e49c4]
WHERE (TIMESTAMP >= @startTime) AND (TIMESTAMP <= @endTime)
GROUP BY operationName

--selecting top ocurrences
INSERT INTO @topTable
SELECT TOP(@top) * FROM @sumsTable
ORDER BY operationAmount DESC

--Summing others and making union with top
SELECT 'OTHER' AS operationName, SUM(operationAmount) as operationAmount FROM @sumsTable
WHERE operationName NOT IN (SELECT operationName FROM @topTable)
UNION
SELECT * FROM @topTable
ORDER BY operationAmount DESC

我的问题是适合这是一个很好的方法,如果有更好的方法,更快的方法......我犯了什么罪吗?我可以摆脱表变量而不使所有的总和超过一次吗?

4

2 回答 2

2

您可以在没有临时表的情况下执行此操作:

SET @top = 10
SET @endTime = '03/11/2013'
SET @startTime = '03/10/2013'

select 
      (case when y.RowID > @top then 'OTHER' else y.operationName end) as operationName,
      sum(y.operationAmount) as operationAmount
from
(
    select 
           row_number() over(order by count(*) desc) as RowID, 
           x.operationName, 
           count(*) AS operationAmount
    from [f6f87bf0-33ab-4882-8674-2cb31e5e49c4] as x
    where (TIMESTAMP >= @startTime) AND (TIMESTAMP <= @endTime)
    group by x.operationName
)
as y
group by (case when y.RowID > @top then 'OTHER' else y.operationName end)
于 2013-04-11T00:57:26.990 回答
0

使用以下 sql,您只需要聚合一次原始表

而不是

row_number() over(order by count(*) desc) as RowID, x.operationName, count(*) AS operationAmount

哪个 count(*) 两次

DECLARE @startTime DATETIME
DECLARE @endTime DATETIME
DECLARE @top INTEGER

SET @endTime = '03/11/2013'
SET @startTime = '03/10/2013'

;WITH cte AS  ( -- get sum for all operations
    SELECT operationName, COUNT(*) AS operationAmount
    FROM [f6f87bf0-33ab-4882-8674-2cb31e5e49c4]
    WHERE (TIMESTAMP >= @startTime) AND (TIMESTAMP <= @endTime)
    GROUP BY operationName
),
cte1 AS ( -- rank totals
    SELECT operationName, operationAmount, ROW_NUMBER()OVER (ORDER BY operationAmount DESC) AS RN  
    FROM cte
) -- get top 10 and others
SELECT (CASE WHEN RN < 10 THEN operationName ELSE 'Others' END) Name, SUM(operationAmount) 
FROM cte1
GROUP BY (CASE WHEN RN < 10 THEN operationName ELSE 'Others' END)
于 2013-04-11T04:25:54.383 回答