我想获得每组的行以及两列的最小值。
我有一张桌子,上面有我想要的物品的清单,以及它们的成本和与我的距离。
mytable:
item | cost | dist
-----+------+---------
1 | $2 | 1.0
1 | $3 | 0.5
1 | $4 | 2.0
2 | $2 | 2.0
2 | $2 | 1.5
2 | $2 | 4.0
2 | $8 | 1.0
2 | $12 | 3.0
3 | $1 | 5.0
对于每一项,我想获得包含最低成本的行,然后,如果有最低成本的倍数,则获得具有最低成本的行
所以我的结果是
item | cost | dist
-----+------+---------
1 | $2 | 1.0
2 | $2 | 1.5
3 | $1 | 5.0
我知道我可以使用
达到此结果SELECT *
, ROW_NUMBER() OVER(PARTITION BY item ORDER BY cost ASC, dist ASC) as [RID]
FROM mytable
WHERE [RID] = 1
但是问题出在我有100,000个项目,每个项目有100,000个列表,对整个表格进行排序变得非常耗时。
由于我只需要每组的前1名,所以我想知道是否还有另一种方法可以得到我想要的结果,而无需对整个10,000,000,000条目的表进行排序。
当前使用SQL Server 2012
答案 0 :(得分:1)
关于这个主题的一篇不错的文章是Itzik Ben Gan-Optimizing TOP N Per Group Queries。本文讨论了串联方法。
例如,如果您的桌子是
CREATE TABLE #YourTable
(
item INT,
cost MONEY CHECK (cost >= 0),
dist DECIMAL(10, 2) CHECK (dist >= 0)
)
您可能会使用
WITH T AS
(
SELECT item,
MIN(FORMAT(CAST(cost * 100 AS INT), 'D10') + FORMAT(CAST(dist * 100 AS INT), 'D10')) AS MinConcat
FROM #YourTable
GROUP BY item
)
SELECT item,
CAST(LEFT(MinConcat,10)/100.0 AS MONEY),
CAST(RIGHT(MinConcat,10)/100.0 AS DECIMAL(10,2))
FROM T
因此,可以在id
上进行一次分组操作(这可以是没有任何排序的哈希聚合)。
您需要注意,当连接的结果的值被当作字符串时,其排序与原始cost, dist
的排序将具有相同的顺序,因此如果您的数据类型不同,上述查询可能需要进行调整
当前,它为cost
保留最左边的10个字符,用整数便士表示,并用前导零值填充,而dist
则类似地作为10位整数。
答案 1 :(得分:0)
您可以这样做
; with c as
(select min(cost) as cost, item
from mytable
group by item)
select t.* from mytable t
inner join c
on c.item = t.item and c.cost=t.cost;
但是,建议您将索引添加到item
和cost
列中,以加快查询速度。
[编辑] 重新阅读OP问题后,如果存在成本联系,应该像以下内容,
; with c as
(select min(cost) as cost, item
from mytable
group by item)
, c2 as (
select t.cost, t.item, min(dist) as dist from mytable t
inner join c
on c.item = t.item and c.cost=t.cost
group by t.cost, t.item)
select t.item,t.cost, c2.dist from mytable t
inner join c2
on c2.item = t.item, and c2.cost = t.cost;
也许有更好的方法,但这应该可行。
答案 2 :(得分:0)
如果您有一个项目表,那么这可能会起作用:
select i.*, t.*
from items i cross apply
(select top (1) t.*
from t
where t.item = i.item
order by cost, dist
) t;
要使其高效,您需要在(item, cost, dist)
上建立索引。
答案 3 :(得分:0)
类似的事情应该起作用:
select
t.item, MIN(t.cost) as mincost, min(t2.mindist) as mindist
from mytable t
inner join (
select item, cost, MIN(dist) as mindist
from mytable
group by
item, cost
) t2 on t.item = t2.item
group by t.item,t2.cost
having MIN(t.cost) = t2.cost