SQL Server:不丢失行且无需XML PATH/STRING_AGG的GROUP BY替代方案
按Name分组生成Group标识(无需XML PATH/STRING_AGG)
当然有啦!你要的是给每个不同的Name分配唯一的组编号,同时保留原表所有字段对吧?完全不用XML PATH或者STRING_AGG这类字符串拼接方法,用窗口函数就能轻松搞定。
原始表
| Id | Name | Date |
|---|---|---|
| 1 | Apple | 2018/20/04 |
| 2 | Apple | 2018/20/03 |
| 3 | Orange | 2018/20/01 |
| 4 | Apple | 2018/20/02 |
| 5 | Orange | 2018/20/03 |
期望结果
| Id | Name | Date | Group |
|---|---|---|---|
| 1 | Apple | 2018/20/04 | 1 |
| 2 | Apple | 2018/20/03 | 1 |
| 3 | Orange | 2018/20/01 | 2 |
| 4 | Apple | 2018/20/02 | 1 |
| 5 | Orange | 2018/20/03 | 2 |
解决方案:使用DENSE_RANK()窗口函数
这里核心用DENSE_RANK()函数,它可以根据Name的唯一值生成连续的组编号,完全不涉及字符串拼接操作。
对应的SQL代码如下:
SELECT Id, Name, Date, DENSE_RANK() OVER (ORDER BY Name) AS [Group] FROM 你的表名;
补充说明
- 默认情况下,
DENSE_RANK()会按照Name的字母排序分配组号(比如Apple在前是1,Orange在后是2),和你示例结果一致。 - 如果希望组号按
Name首次出现的顺序分配(而不是字母顺序),可以结合嵌套窗口函数来实现:
SELECT Id, Name, Date, DENSE_RANK() OVER (ORDER BY FirstOccurId) AS [Group] FROM ( SELECT *, MIN(Id) OVER (PARTITION BY Name) AS FirstOccurId FROM 你的表名 ) t;
这样组号会严格按照每个Name第一次出现的先后顺序来生成,更贴合业务场景的需求。
内容的提问来源于stack exchange,提问作者FLash
相关产品推荐
相关产品推荐

