如何在SQL中按字段分区查询单条记录?SQL Server取各名称最新数据
获取每个分组的最新记录(SQL Server解决方案)
先看你的示例数据:
| Timestamp | Name | Price |
|---|---|---|
| 2018-01-02 | Name1 | 0.10 |
| 2018-01-03 | Name1 | 0.20 |
| 2018-01-04 | Name1 | 0.30 |
| 2018-01-02 | Name2 | 0.40 |
| 2018-01-03 | Name2 | 0.50 |
| 2018-01-04 | Name2 | 0.60 |
| 2018-01-02 | Name3 | 0.70 |
| 2018-01-03 | Name3 | 0.80 |
| 2018-01-05 | Name3 | 0.90 |
要得到每个Name对应的最新Timestamp记录,用窗口函数是最直观高效的方式,直接上代码:
SELECT Timestamp, Name, Price FROM ( SELECT Timestamp, Name, Price, -- 按Name分组,每组内按Timestamp倒序编号 ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Timestamp DESC) AS rn FROM YourTableName -- 替换成你的实际表名 ) AS ranked_data WHERE rn = 1; -- 只取每组的第一条(最新的记录)
执行这个查询后,就能得到你想要的结果:
| Timestamp | Name | Price |
|---|---|---|
| 2018-01-04 | Name1 | 0.30 |
| 2018-01-04 | Name2 | 0.60 |
| 2018-01-05 | Name3 | 0.90 |
原理解释:
PARTITION BY Name:把整个数据集按Name拆分成独立的小组,每个Name单独成一组ORDER BY Timestamp DESC:在每个小组内部,按照Timestamp从新到旧排序ROW_NUMBER():给每个小组里的记录按排序结果编号,最新的那条会被标记为1- 外层查询筛选
rn = 1的记录,就得到了每个Name的最新条目
特殊情况处理:
如果同一个Name存在多条Timestamp完全相同的最新记录,上面的ROW_NUMBER()会随机选一条返回。如果想保留所有同时间的记录,可以换成RANK()或者DENSE_RANK():
SELECT Timestamp, Name, Price FROM ( SELECT Timestamp, Name, Price, RANK() OVER (PARTITION BY Name ORDER BY Timestamp DESC) AS rn FROM YourTableName ) AS ranked_data WHERE rn = 1;
关于“按字段分区查询单条记录”的通用方法
其实上面的窗口函数就是典型的分区取单条记录的实现方式,核心思路是:
- 用
PARTITION BY 字段名指定你要分组的字段(比如这里的Name,也可以是多个字段组合) - 用
ORDER BY定义每个分组内的排序规则,确定哪条是你需要的目标记录(比如最新时间、最大价格等) - 用窗口函数(ROW_NUMBER/RANK/DENSE_RANK)给分组内的记录编号
- 在外层查询筛选编号为1的记录,得到每个分区的目标条目
另外,也可以用子查询关联的方式实现,比如先找出每个分组的最大Timestamp,再关联原表:
SELECT t.Timestamp, t.Name, t.Price FROM YourTableName t INNER JOIN ( -- 先获取每个Name的最新Timestamp SELECT Name, MAX(Timestamp) AS LatestTimestamp FROM YourTableName GROUP BY Name ) AS latest_dates ON t.Name = latest_dates.Name AND t.Timestamp = latest_dates.LatestTimestamp;
这种方法逻辑也很清晰,但窗口函数的写法更灵活,适合处理更复杂的排序和筛选需求。
内容的提问来源于stack exchange,提问作者Brett
相关产品推荐
相关产品推荐

