【问题标题】:Closest Timestamp from a Table表中最近的时间戳
【发布时间】:2013-06-15 16:48:46
【问题描述】:

我有 3 张桌子。

Table 1 has 2 fields : Time/Value

Table 2 has 2 fields : Time/Value

Table 3 has 1 field : Time

我想为表 3 中的每个时间找到表 1 和表 2 中最接近时间字段的值。

表 1 和表 2 中的时间精度约为毫秒。表 3 中的时间精度为 1 秒。

是否可以在 SQL 查询中这样做而不必自己使用循环解析表?

【问题讨论】:

  • 是的,使用en.wikipedia.org/wiki/Join_(SQL)。如果仍然卡住,请显示您已有的代码。
  • 您能否用您正在使用的 RDBMS(MySQL、Oracle、SQL Server、Postgres 等)标记您的问题。如果这是 Oracle、SQL Server 或 Postgres(或任何其他支持窗口功能的),那么这将有所帮助:stackoverflow.com/questions/13929053/…
  • @mb21 - 我认为您没有阅读问题

标签: sql sql-server


【解决方案1】:

您可以在 SQL 中执行此操作,但由于 SQL 可用的工具会很慢,对于 Table3 的每一行,您必须查找 Table1 和 Table2 的所有行。如果您以更通用的语言手动编写解决方案,您可以针对问题域进行优化。如果你只是将它作为一个临时请求,SQL 将是最容易编码的,看起来像这样:

SELECT t3.time,
  (SELECT TOP 1 t1.value
   FROM t1
   ORDER BY ABS(DATEDIFF(ms,t3.time,t1.time)) ASC
  ) as t1value,
  (SELECT TOP 1 t2.value
   FROM t2
   ORDER BY ABS(DATEDIFF(ms,t3.time,t2.time)) ASC
  ) as t2value
FROM t3

这是如何工作的

对于 t3 中的每一行,按时间差对 t1 和 t2 进行选择,并且只取最小的一个。

关于速度的说明

此代码将在O(N3 * N1) + O(N3 * N2) 中运行。如果您手动编写了一个好的算法,您将能够获得O(N3 * log(N1)) + O(N3 * log(N2)。 (因为您可以在时间上进行快速最近的搜索)。

【讨论】:

  • 谢谢它我正在寻找的东西。但是,由于我在每个表中有几十万个条目,因此查询太长而无法处理。我别无选择,只能解析一次并在运行时分配每个时间戳。但是谢谢,它可以测试我数据的一小部分的准确性。
【解决方案2】:

这是执行此操作的一种方法:

select t3.Time
  , t1Time = case when abs(datediff(ms, t1Below.Time, t3.Time))
      <= abs(datediff(ms, t1Above.Time, t3.Time))
    then t1Below.Time
    else t1Above.Time
    end
  , t1Value = case when abs(datediff(ms, t1Below.Time, t3.Time))
      <= abs(datediff(ms, t1Above.Time, t3.Time))
    then t1Below.Value
    else t1Above.Value
    end
  , t2Time = case when abs(datediff(ms, t2Below.Time, t3.Time))
      <= abs(datediff(ms, t2Above.Time, t3.Time))
    then t2Below.Time
    else t2Above.Time
    end
  , t2Value = case when abs(datediff(ms, t2Below.Time, t3.Time))
      <= abs(datediff(ms, t2Above.Time, t3.Time))
    then t2Below.Value
    else t2Above.Value
    end
from t3
  outer apply (select top 1 t1Below.*
              from t1 t1Below
              where t3.Time >= t1Below.Time
              order by t1Below.Time desc) t1Below
  outer apply (select top 1 t1Above.*
              from t1 t1Above
              where t3.Time <= t1Above.Time
              order by t1Above.Time) t1Above
  outer apply (select top 1 t2Below.*
              from t2 t2Below
              where t3.Time >= t2Below.Time
              order by t2Below.Time desc) t2Below
  outer apply (select top 1 t2Above.*
              from t1 t2Above
              where t3.Time <= t2Above.Time
              order by t2Above.Time) t2Above

SQL Fiddle with demo.

这种方法在每个 t3 时间之前和之后找到最近的 t1t2 时间/值,然后找出其中的哪一个在select 语句中使用的前/后行。

这种方式的优点是 SQL Server 可以有效地使用索引来获取之前/之后的值;为计算每个 t3 时间使用哪个之前/之后值所做的工作应该通过有效检索之前/之后值来抵消。

【讨论】:

    猜你喜欢
    • 2021-04-17
    • 2020-05-26
    • 2011-12-31
    • 2015-08-19
    • 2014-02-07
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多