我希望每组获得一行(根据A列),该行应该是该组中具有最高“B”值的行。顺便说一下,如果需要,(A,B)是唯一的。我编写了以下sql代码,它完成了这项工作。我想知道有更高效的东西吗?我更喜欢纯SQL的东西,但我将在SQL SERVER 2012中的存储过程中使用它。
DECLARE @mytab TABLE (A INT, B INT, C INT)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 1, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 2, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 3, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (2, 2, 2)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 3, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 2, 2)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 1, 3)
;WITH numbered AS
(
SELECT *, rn=ROW_NUMBER() OVER (PARTITION BY A ORDER BY B DESC)
FROM @mytab AS m
)
SELECT A, B, C
FROM numbered
WHERE rn=1
返回以下
A B C
1 3 1
2 2 2
3 3 1
答案 0 :(得分:2)
在我的测试中,使用您的测试数据x 100,000行,以下查询的效果提高了35%。
SELECT A, B, C
FROM @mytab mytab_outer
WHERE B = (SELECT MAX(B) FROM @mytab WHERE A = mytab_outer.A)
如果你看一下执行计划,这会胜出,因为对于你的查询,它会把所有时间花在排序函数上(96%)。
让我对这个问题感到困惑的是,如果我将其转换为临时表并为A和B创建主键(您可以为表变量创建主键 - 我认为您的查询会做得更好 - 我当时忘记了)。在我再次测试之前,我确保运行DBCC FREEPROCCACHE
。
上述查询运行 75次更快,而您的查询执行时间与之前相同。它没有使用主键创建的聚簇索引。即使我为A列和B列添加和索引,它仍然没有帮助。我尝试使用表提示,但无济于事。
因此,从我的测试来看,你的方法似乎是效率最低的方法,特别是如果有索引的话。
修改强> 所以我弄清楚为什么带窗口函数的查询做得很糟糕。
如果我删除order by子句中的方向,那么它使用我创建的索引,但当然输出是错误的。因此,如果使用表变量,此查询的结果将始终是错误的,因为您无法控制索引的排序方向。
答案 1 :(得分:0)
在子查询/ cte中使用ROW_NUMBER()
通常是解决此问题的最佳解决方案。大多数替代方案需要JOIN
,因此效果不佳。