SQL Server 2016:获取各仪表首个及最后一个数据点的时间与值
解决SQL Server中获取仪表首尾数据点及对应值的问题
你已经迈出了第一步,拿到了每个仪表的最早和最晚时间,现在只需要把对应的Value字段关联进来就行。这里给你两种实用的方法,都适配SQL Server 2016:
方法一:使用窗口函数(推荐,高效简洁)
窗口函数是处理这类"分组取首尾"场景的绝佳选择,只需要扫描一次DataPoints表就能完成排序和筛选:
WITH RankedData AS ( SELECT MeterId, DateTime, Value, -- 按仪表分组,按时间升序排,第一条就是最早的数据 ROW_NUMBER() OVER (PARTITION BY MeterId ORDER BY DateTime ASC) AS rn_first, -- 按仪表分组,按时间降序排,第一条就是最晚的数据 ROW_NUMBER() OVER (PARTITION BY MeterId ORDER BY DateTime DESC) AS rn_last FROM DataPoints ) SELECT m.Name AS [Meter Name], first_dt.DateTime AS [First DateTime], first_dt.Value AS [First Value], last_dt.DateTime AS [Last DateTime], last_dt.Value AS [Last Value] FROM Meters m -- 左连接确保没有数据的仪表也能出现在结果里 LEFT JOIN RankedData first_dt ON m.MeterId = first_dt.MeterId AND first_dt.rn_first = 1 LEFT JOIN RankedData last_dt ON m.MeterId = last_dt.MeterId AND last_dt.rn_last = 1;
说明:
PARTITION BY MeterId表示按仪表ID分组处理每个仪表的数据rn_first=1筛选出每个仪表最早的那条记录,rn_last=1筛选出最晚的那条- 左连接保留了所有仪表,即使某个仪表没有任何数据点,对应的时间和值会显示
NULL
方法二:子查询关联(适合理解基础关联逻辑)
如果你更习惯用子查询,也可以先找到每个仪表的首尾时间,再回查对应的Value:
SELECT m.Name AS [Meter Name], min_dt.DateTime AS [First DateTime], min_dt.Value AS [First Value], max_dt.DateTime AS [Last DateTime], max_dt.Value AS [Last Value] FROM Meters m LEFT JOIN ( -- 子查询获取每个仪表最早时间对应的记录 SELECT MeterId, DateTime, Value FROM DataPoints dp WHERE (MeterId, DateTime) IN ( SELECT MeterId, MIN(DateTime) FROM DataPoints GROUP BY MeterId ) ) min_dt ON m.MeterId = min_dt.MeterId LEFT JOIN ( -- 子查询获取每个仪表最晚时间对应的记录 SELECT MeterId, DateTime, Value FROM DataPoints dp WHERE (MeterId, DateTime) IN ( SELECT MeterId, MAX(DateTime) FROM DataPoints GROUP BY MeterId ) ) max_dt ON m.MeterId = max_dt.MeterId;
注意:
如果同一个仪表在同一时间有多个数据点,这个方法会返回多条对应记录。如果需要确保每个仪表只取一条,可以在子查询里加上TOP 1和ORDER BY,或者改用方法一的窗口函数。
内容的提问来源于stack exchange,提问作者pitersmx
相关产品推荐
相关产品推荐

