如何从使用group by命令检索到的结果中获取每个组的第一条记录

24
假设我的输入是:
ID  GroupID  Qty
1         1  100
2         1  200
3         1  300
4         2  98
5         2  198
6         3  175
7         3  275
8         3  375
9         4  215

输出应该是
ID   GroupID    Qty
 1         1    100
 4         2    98
 6         3    175
 9         4    215

有人可以帮我用SQL Server的T-SQL查询来完成吗?

你能再清楚一些吗?输入到哪里?为什么输出应该是那样的?你是输入到一个表格中吗?也许只是格式不够清晰。 - Ramy
定义"First"。首先按照什么顺序?在你的示例数据中,Qty总是在按id分组时升序排列吗? - Martin Smith
1
高质量的问题!您可能已经提到了您正在使用的SQL Server版本。 - Christiaan Westerbeek
3个回答

46
declare @T table (ID int, GroupID int, Qty int)
insert into @T values
(1, 1, 100),
(2, 1, 200),
(3, 1, 300),
(4, 2, 98),
(5, 2, 198),
(6, 3, 175),
(7, 3, 275),
(8, 3, 375),
(9, 4, 215)

;with cte as
(
  select
    ID,
    GroupID,
    Qty,
    rank() over(partition by GroupID order by ID) as rn
  from @T
)  
select ID, GroupID, Qty
from cte
where rn = 1

太好了!不过在我的情况下,我必须把rank()改为ROW_NUMBER()。顺便说一句,谢谢。 - Amogh Natu
很棒的答案。CTE适用于MSSQL 2005及以上版本,而不适用于MSSQL 2000。 - Christiaan Westerbeek
rank() 允许存在并列情况,并将并列的行分配相同的排名,例如 [1, 4, 4, 5] 的排名为 [1, 2, 2, 4]。而 row_number() 则按顺序分配不带并列的连续数字,返回结果为 [1, 2, 3, 4] - BallpointBen

6

编辑

SELECT 
    MIN(ID) ,
    GroupID,
    (SELECT TOP 1 Qty FROM @TABLE T2 WHERE T2.ID = MIN(T1.ID))
FROM 
    @TABLE T1
GROUP BY
    GroupID

输入

 ID GroupID   Qty
    1   1   100
    2   1   200
    3   1   300
    4   2   98
    5   2   198
    6   3   175
    7   3   275
    8   3   375
    9   4   215

输出

1   1   100
4   2   98
6   3   175
9   4   215

3

在我看来,最好、最灵活的方法是使用ROW_NUMBER()。下面是我为您的示例测试过的代码,请将tmpTable替换为您的表名:

SELECT a.* FROM tmpTable a INNER JOIN 
(SELECT    ROW_NUMBER() over(PARTITION BY GroupID ORDER BY ID, GroupID) AS SEQ, tmpTable.*
FROM            tmpTable) b
ON a.ID = b.ID AND a.GroupID = b.GroupID
WHERE b.SEQ = 1

阅读更多关于如何使用ROW_NUMBER的内容: https://learn.microsoft.com/en-us/sql/t-sql/functions/row-number-transact-sql


如果您在分区中按照排序的数据具有相同值的多个副本(100,100,100,200,300),则使用 rank() 将返回重复条目,因为每个重复值都获得相同的排名。我同意 row_number() 方法可能更灵活地选择第一个值。但是,我无法确定 row_number()rank() 在性能上的影响。 - gbeaven
@gbeaven,为了简单起见,我没有添加另一层。为了提高性能,我会选择 SEQ = 1 的记录,然后与主表连接。这将产生一个具有较小记录子集的联合查询(为了提高性能,WHERE b.SEQ = 1 应该在子查询中通过添加另一个嵌套层)。 - Richard Mneyan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接