获取最接近另一个表中每行的时间的行

时间:2017-04-22 20:51:07

标签: sql sql-server

问题:

嗨,我有一张包含来自一堆传感器的历史数据的表格,我正在尝试为最接近所需时间的每个历史数据记录获取一行。例如,我想让记录最接近每一分钟。

我已将问题简化为以下内容,如果我可以解决,我可以用来通知我的一般解决方案:

按如下方式选择两个表:

CREATE TABLE [TempDataTable](
[DataIndex] [int] IDENTITY(0,2) NOT NULL,
[DataName] [varchar](40) NOT NULL,
[DataValue] [decimal](10,2) NOT NULL,
[DataTimeStamp] [datetime2](7)
)

CREATE TABLE [TempTargetTable](
[TargetIndex] [int] IDENTITY(1,2) NOT NULL,
[TargetTime] [datetime2](7)
)

对于TempTargetTable中的每一行,获取TempDataTableTempDataTable.DataTimeStamp最接近TempTargetTable.TargetTime的行

如果我能做到这一点,我相信我可以弄清楚剩下的,但我不知道如何让这第一步开始工作。为了便于测试您的代码,我可以提供以下内容,使用一些测试数据填充两个表:

有用的测试数据:

INSERT INTO [TempDataTable]
    ([DataName],
    [DataValue],
    [DataTimeStamp])
VALUES
    ('Sensor',0,    '2017-01-01 00:00:00'),
    ('Sensor',0.5,  '2017-01-01 00:00:17'),
    ('Sensor',1,    '2017-01-01 00:01:03'),
    ('Sensor',1.5,  '2017-01-01 00:01:30'),
    ('Sensor',1.5,  '2017-01-01 00:01:38'),
    ('Sensor',2,    '2017-01-01 00:02:01'),
    ('Sensor',2.5,  '2017-01-01 00:02:15'),
    ('Sensor',3,    '2017-01-01 00:02:56'),
    ('Sensor',3.5,  '2017-01-01 00:03:27'),
    ('Sensor',4,    '2017-01-01 00:04:01'),
    ('Sensor',5,    '2017-01-01 00:05:00'),
    ('Sensor',5.5,  '2017-01-01 00:05:15'),
    ('Sensor',5.5,  '2017-01-01 00:05:46'),
    ('Sensor',6,    '2017-01-01 00:06:10'),
    ('Sensor',7,    '2017-01-01 00:06:57'),
    ('Sensor',7.5,  '2017-01-01 00:07:13'),
    ('Sensor',8,    '2017-01-01 00:08:01'),
    ('Sensor',9,    '2017-01-01 00:09:03')

INSERT INTO [TempTargetTable]
    ([TargetTime])
VALUES
    ('2017-01-01 00:00:00'),
    ('2017-01-01 00:01:00'),
    ('2017-01-01 00:02:00'),
    ('2017-01-01 00:03:00'),
    ('2017-01-01 00:04:00'),
    ('2017-01-01 00:05:00'),
    ('2017-01-01 00:06:00'),
    ('2017-01-01 00:07:00'),
    ('2017-01-01 00:08:00'),
    ('2017-01-01 00:09:00')

3 个答案:

答案 0 :(得分:1)

对于您发布的当前问题(简化版),我执行了以下操作:

交叉加入表格以使每个目标时间与每个现​​有数据时间戳相区别。 然后应用DENSE_RANK函数,该函数将为每个TargetTime提供排名,然后仅选择具有最小差异(毫秒)的那些记录。

您可以找到有效的解决方案here

 select TargetIndex, TargetTime, DataIndex, DataName, DataValue, DataTimeStamp
 from
  (
   select t.*, DENSE_RANK() OVER(PARTITION BY t.targetindex ORDER BY t.diff) as Rank
   from 
    (
      select tg.targetindex, tg.targettime, t.dataindex, t.dataname, t.datavalue, t.datatimestamp, abs(datediff(ms, tg.TargetTime, t.DataTimeStamp)) diff
      from TempDataTable t cross join TempTargetTable tg
    ) t
 ) f 
 where Rank = 1

答案 1 :(得分:0)

如果您想要每个日历分钟中的第一条记录,可以使用arr

arr[id]

答案 2 :(得分:0)

如果我正在阅读您的问题,那么即使是在前一分钟,您也希望获得最接近的记录。如果是这样,你可以这个查询。我分多步完成,所以你可以轻松地跟随(我希望)

我做了什么:

  • 找到最近的分钟,如果秒>> = 30轮到下一分钟,否则保持实际分钟
  • 计算以秒为单位的差异并找到它的绝对值
  • 获取与时间点最接近的值

查询

SELECT tempd.TargetTime, tdfinal.DataName, tdfinal.DataValue, tdfinal.DataTimeStamp
FROM @TempTargetTable as tempd
LEFT OUTER JOIN
   (SELECT tdseconds.*, ROW_NUMBER() OVER(PARTITION BY closestMinute ORDER BY secondDiff) AS r
    FROM (SELECT td.*, ABS(DATEDIFF(SECOND, DataTimeStamp, closestMinute)) AS secondDiff
          FROM (SELECT DataName,DataValue,DataTimeStamp,
                  CONVERT(DATETIME,CONVERT(DATE, datatimestamp, 121)) + 
                  CONVERT (DATETIME,TIMEFROMPARTS(DATEPART(HOUR, datatimestamp), 
                             CASE WHEN DATEPART(SECOND, DataTimeStamp) >= 30 
                                    THEN DATEPART(MINUTE, DATATimeStamp) + 1 
                                    ELSE DATEPART(MINUTE, DATATimeStamp) END, 0,0,0), 121) AS closestMinute
                FROM @TempDataTable ) AS td
          ) AS tdseconds
   ) AS tdfinal
ON tdfinal.closestMinute = tempd.TargetTime
WHERE tdfinal.r = 1

结果

TargetTime               DataName  DataValue  DataTimeStamp
2017-01-01 00:00:00.000  Sensor    0.00       2017-01-01 00:00:00.000
2017-01-01 00:01:00.000  Sensor    1.00       2017-01-01 00:01:03.000
2017-01-01 00:02:00.000  Sensor    2.00       2017-01-01 00:02:01.000
2017-01-01 00:03:00.000  Sensor    3.00       2017-01-01 00:02:56.000
2017-01-01 00:04:00.000  Sensor    4.00       2017-01-01 00:04:01.000
2017-01-01 00:05:00.000  Sensor    5.00       2017-01-01 00:05:00.000
2017-01-01 00:06:00.000  Sensor    6.00       2017-01-01 00:06:10.000
2017-01-01 00:07:00.000  Sensor    7.00       2017-01-01 00:06:57.000
2017-01-01 00:08:00.000  Sensor    8.00       2017-01-01 00:08:01.000
2017-01-01 00:09:00.000  Sensor    9.00       2017-01-01 00:09:03.000