[英]Microsoft SQL Server : return only the rows with the most recent date for each unique ID
我有一些具有DeviceID
列,扫描时间列和其他一些列的数据。
对于每个deviceID,我只想根据扫描时间返回最近的行。
我正在尝试创建此查询,以便可以将其用作视图并报告数据。
该数据库是Microsoft SQL Server数据库,我正在从SQL Server 2014 Management Studio运行查询。
我最接近使它起作用的是:
SELECT
DeviceID,
AVSolutionName,
DefinitionsUpToDate,
ScanningEnabled,
Expired,
ScanTime
FROM
dbo.fact_AVSecurity
WHERE
(ScanTime IN (SELECT DISTINCT MAX(ScanTime) AS LastScan
FROM dbo.fact_AVSecurity AS Avs
GROUP BY DeviceID))
不幸的是,这将为同一ID返回多个值。
ScanTime ScanningEnabled Expired DeviceID DefinitionsUpToDate AVSolutionName
10/12/2018 10:13 TRUE FALSE 15994 TRUE Webroot SecureAnywhere
4/12/2018 14:30 TRUE TRUE 15994 TRUE Webroot SecureAnywhere
我想要返回的只是最近的第一行:
ScanTime ScanningEnabled Expired DeviceID DefinitionsUpToDate AVSolutionName
10/12/2018 10:13 TRUE FALSE 15994 TRUE Webroot SecureAnywhere
我已经尝试过不同的方法,例如: SQL-仅返回最近的行
但是似乎无法使他们工作。 我不确定这是我做错了还是我使用的特定品牌的SQL没有执行“ top 1”操作。
有什么方法可以做我想要的吗? 我和我的财产有多近?
使用带有CTE的窗口功能?
With CTE AS (
SELECT t.DeviceID
, t.AVSolutionName
, t.DefinitionsUpToDate
, t.ScanningEnabled
, t.Expired
, t.ScanTime
, Row_Number() over (partition by DeviceID order by scanTime Desc) RN
FROM dbo.fact_AVSecurity t)
SELECT *
FROM CTE
WHERE RN=1
检查一下:
SELECT t.DeviceID, t.AVSolutionName, t.DefinitionsUpToDate, t.ScanningEnabled, t.Expired, t.ScanTime
FROM dbo.fact_AVSecurity AS t
WHERE t.ScanTime = (SELECT MAX(Avs.ScanTime) FROM dbo.fact_AVSecurity AS Avs WHERE Avs.DeviceID = t.DeviceID)
对于每个DeviceID
提取具有ScanTime = MAX(ScanTime)
您已接近解决方案。 您只需要在相关子查询中进行一些更改:
在您的子查询中添加WHERE
条件,以将搜索限制为当前DeviceID
无需使用IN
子句来匹配子查询,相等就可以了,因为无论如何只期望一条记录
无需使用DISTINCT
因为您已经在使用GROUP BY
查询:
SELECT
t.DeviceID,
t.AVSolutionName,
t.DefinitionsUpToDate,
t.ScanningEnabled,
t.Expired,
t.ScanTime
FROM dbo.fact_AVSecurity AS t
WHERE t.ScanTime =
(SELECT MAX(ScanTime) AS LastScan
FROM dbo.fact_AVSecurity AS Avs
WHERE deviceID = t.deviceID
GROUP BY DeviceID
)
如果你有你的表自动递增列(你一般应该有一个对每个表),用这个来代替时间戳,因为SQL服务器DateTime
类型只有一个1/300 个第二的分辨率和不应假设成为唯一的时间戳。
SELECT X.LastEntryID, DeviceID = Y.ID, ...
FROM
(
SELECT LastEntryID = MAX(ID)--latest entry for the device
FROM dbo.fact_AVSecurity
GROUP BY DeviceID--you don't even need to return DeviceID since ID is auto-increment and thus unique in the table
) AS X
INNER JOIN dbo.fact_AVSecurity AS Y ON
Y.ID = X.LastEntryID
假设您不回溯数据或使用IDENTITY_INSERT
填充数据
最后一个选择,因为我没有提到
您可以将WITH TIES
与Row_Number()配合使用
也就是说, xQbert的解决方案(+1)的性能更高,尤其是对于较大的表
例
SELECT Top 1 with ties *
FROM dbo.fact_AVSecurity
Order By Row_Number() over (partition by DeviceID order by scanTime Desc)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.