我有一个表,主键(bigint),日期时间,值,foreignKey到配置表,包含100,000行。我希望能够获得一个可变时间间隔的行。例如。
Select Timestamp, value from myTable where configID=3
AND{most recent for 15 min interval}
我有一个CTE查询,它返回间隔时间间隔的多行
WITH Time_Interval(timestamp, value, minutes)
AS
(
Select timestamp, value, DatePart(Minute, Timestamp) from myTable
Where Timestamp >= '12/01/2012' and Timestamp <= 'Jan 10, 2013' and
ConfigID = 435 and (DatePart(Minute, Timestamp) % 15) = 0
)
Select Timestamp, value, minutes from Time_Interval
group by minutes, value, timestamp
order by Timestamp
如:
2012-12-19 18:15:22.040 6.98 15
2012-12-19 18:15:29.887 6.98 15
2012-12-19 18:15:33.480 7.02 15
2012-12-19 18:15:49.370 7.01 15
2012-12-19 18:30:41.920 6.95 30
2012-12-19 18:30:52.437 6.93 30
2012-12-19 19:15:18.467 7.13 15
2012-12-19 19:15:34.250 7.11 15
2012-12-19 19:15:49.813 7.12 15
但是可以看出,第1个15分钟间隔有4个,下一个间隔有2个等等...更糟糕的是, 如果没有在15分钟的确切时间戳上获得数据,则没有价值。
我想要的是十五分钟间隔的最新值...如果该间隔的唯一数据是在间隔开始后的1秒内发生的。
我正在考虑Lead / over但是......这些行并没有这样的方式。主键是一个bigInt,是一个聚簇索引。 timstamp列和ConfigID列都是Indexed。上面的查询在一秒钟内返回4583行。
感谢您的帮助。
答案 0 :(得分:1)
如果你想在15分钟的间隔内分区,请在几分钟内使用datediff并除以15。 并使用该分区对每个间隔进行排名。
WITH myTbl AS
(
SELECT
timestamp, value,
RANK() OVER (PARTITION BY (DATEDIFF(Mi,0, Timestamp)/15) ORDER BY Timestamp desc) RK
FROM myTable
--WHERE Timestamp BETWEEN '' AND ''
)
SELECT * FROM myTble
WHERE RK <= 1
答案 1 :(得分:1)
尝试使用此尺寸。当您有给定间隔的多个时间戳时,它甚至会处理为实例返回的一行。 注意:这假设您的Bigint PK列命名为:idx。如果不是,请替换“idx”。
;WITH Interval_Helper([minute],minute_group)
AS
(
SELECT 0, 1 UNION SELECT 1, 1 UNION SELECT 2, 1 UNION SELECT 3, 1 UNION SELECT 4, 1
UNION SELECT 5, 1 UNION SELECT 6, 1 UNION SELECT 7, 1 UNION SELECT 8, 1 UNION SELECT 9, 1
UNION SELECT 10, 1 UNION SELECT 11, 1 UNION SELECT 12, 1 UNION SELECT 13, 1 UNION SELECT 14, 1
UNION SELECT 15, 2 UNION SELECT 16, 2 UNION SELECT 17, 2 UNION SELECT 18, 2 UNION SELECT 19, 2
UNION SELECT 20, 2 UNION SELECT 21, 2 UNION SELECT 22, 2 UNION SELECT 23, 2 UNION SELECT 24, 2
UNION SELECT 25, 2 UNION SELECT 26, 2 UNION SELECT 27, 2 UNION SELECT 28, 2 UNION SELECT 29, 2
UNION SELECT 30, 3 UNION SELECT 31, 3 UNION SELECT 32, 3 UNION SELECT 33, 3 UNION SELECT 34, 3
UNION SELECT 35, 3 UNION SELECT 36, 3 UNION SELECT 37, 3 UNION SELECT 38, 3 UNION SELECT 39, 3
UNION SELECT 40, 3 UNION SELECT 41, 3 UNION SELECT 42, 3 UNION SELECT 43, 3 UNION SELECT 44, 3
UNION SELECT 45, 4 UNION SELECT 46, 4 UNION SELECT 47, 4 UNION SELECT 48, 4 UNION SELECT 49, 4
UNION SELECT 50, 4 UNION SELECT 51, 4 UNION SELECT 52, 4 UNION SELECT 53, 4 UNION SELECT 54, 4
UNION SELECT 55, 4 UNION SELECT 56, 4 UNION SELECT 57, 4 UNION SELECT 58, 4 UNION SELECT 59, 4
)
,Time_Interval([timestamp], value, [date], [hour], minute_group)
AS
(
SELECT A.[Timestamp]
,A.value
,CONVERT(smalldatetime, CONVERT(char(10), A.[Timestamp], 101))
,DATEPART(HOUR, A.[Timestamp])
,B.minute_group
FROM myTable A
JOIN Interval_Helper B
ON (DATEPART(minute, A.[Timestamp])) = B.[minute]
AND A.[Timestamp] >= '12/01/2012'
AND A.[Timestamp] <= '01/10/2013'
AND A.ConfigID = 435
)
,Time_Interval_TimeGroup([date], [hour], [minute], MaxTimestamp)
AS
(
SELECT [date]
,[hour]
,minute_group
,MAX([Timestamp]) as MaxTimestamp
FROM Time_Interval
GROUP BY [date]
,[hour]
,minute_group
)
,Time_Interval_TimeGroup_Latest(MaxTimestamp, MaxIdx)
AS
(
SELECT MaxTimestamp
,MAX(idx) as MaxIdx
FROM myTable A
JOIN Time_Interval_TimeGroup B
ON A.[Timestamp] = B.MaxTimestamp
GROUP BY MaxTimestamp
)
SELECT A.*
FROM myTable A
JOIN Time_Interval_TimeGroup_Latest B
ON A.idx = B.MaxIdx
ORDER BY A.[timestamp]
这是另一个来自@MntManChris的聪明时间组功能:
CREATE FUNCTION dbo.fGetTimeGroup (@DatePart tinyint, @Date datetime)
RETURNS int
AS
BEGIN
RETURN CASE @DatePart
WHEN 1 THEN DATEPART(mi, @Date)
WHEN 2 THEN DATEPART(mi, @Date)/5 + 1 -- 5 min
WHEN 3 THEN DATEPART(mi, @Date)/15 + 1 -- 15 min
WHEN 4 THEN DATEPART(mi, @Date)/30 + 1 -- 30 min
WHEN 5 THEN DATEPART(hh, @Date) -- hr
WHEN 6 THEN DATEPART(hh, @Date)/6 + 1 -- 6 hours
WHEN 7 THEN DATEPART(hh, @Date)/12 + 1 -- 12 hours
WHEN 8 THEN DATEPART(d, @Date) -- day
ELSE -1
END
END
答案 2 :(得分:1)
正如我上面的评论所说,我已经使用了Rob的答案,但是使用了一个用户函数来消除Interval_Helper表和第一个连接。这是用户功能的代码。
BEGIN
DECLARE @Ans integer
if @DatePart = 1 -- min
return DATEPART(mi, @Date)
if @DatePart = 2 -- 5 min
return DatePart(mi,@Date)/5 + 1
if @DatePart = 3 -- 15 min
return DatePart(mi,@Date)/15 + 1
if @DatePart = 4 -- 30min
return DatePart(mi,@Date)/30 + 1
if @DatePart = 5 -- hr
return DATEPART(hh, @Date)
if @DatePart = 6 -- 6 hours
return DATEPART(hh, @Date)/6 + 1
if @DatePart = 7 -- 12 hours
return DATEPART(hh, @Date)/12 + 1
if @DatePart = 8 -- day
return DATEPART(d, @Date)
return -1
END
然后使Time_Interval表看起来像
;WITH Time_Interval([timestamp], value, [date], [day], time_group)
AS
(
SELECT A.[Timestamp]
,A.value
,CONVERT(smalldatetime, CONVERT(char(10), A.[Timestamp], 101))
,DATEPART(dd, A.[Timestamp])
,dbo.fGetTimeGroup(@tInterval, A.[Timestamp]) as 'time_group'
FROM myTable A
where
A.[Timestamp] >= '12/01/2012'
AND A.[Timestamp] <= '01/10/2013'
AND A.ConfigID= 435
)
由于@TimeInterval从1小时到6小时,或12小时或每天,从“小时”切换到“天”。我还必须将Time_Interval_TimeGroup表切换为按[小时]分组到按[天]分组,当然还要在选择列表中进行分组。
由于这是一个更大的抽象数据库模式的一部分,其中有问题的表和数据库都是ConfigID的函数,因此需要动态SQL,因此在分组中实现此开关不是问题,我只是简单地实现了两个不同的dynSql基于@TimeInterval
值的部分由于