【问题标题】:Datediff between non-consecutive rows in a table表中非连续行之间的日期差异
【发布时间】:2010-01-11 16:47:10
【问题描述】:

我想从下表 1 中取平均时间差。这些值不是连续的,有时时间值会重复,所以我需要 1)按时间排序,2)丢弃非唯一值,3)执行时间差(以毫秒为单位),然后 4)平均得到的时间差价值观。此外,我想 5)将 datediff 操作限制在选定的时间范围内,例如 WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp = '20091220 11:59:56.8'。我很困惑如何把这一切放在一起!

表 1:
_时间戳
2009-12-20 11:59:56.0
2009-12-20 11:59:56.5
2009-12-20 11:59:56.3
2009-12-20 11:59:56.4
2009-12-20 11:59:56.4
2009-12-20 11:59:56.9

【问题讨论】:

  • 您想要“平均时间”,还是想要距离下一个事件的时间? (直到下一个日期条目的持续时间以毫秒为单位)......“平均时间”没有多大意义。如果这是你想要的,请解释一下。
  • 我想取行排序后的平均时间差。位于所需日期范围内的已排序且唯一的行是 2009-12-20 11:59:56.3、2009-12-20 11:59:56.4 和 2009-12-20 11:59:56.5。这些值之间的时间差(以毫秒为单位)为 100、100。因此这两个时间差的平均值为 100 毫秒。
  • 您认为上述时间的答案是什么?

标签: sql sql-server join unique datediff


【解决方案1】:

这是一个有效且不丑陋的:

;WITH Time_CTE AS
(
    SELECT
        MIN(_Timestamp) AS dt,
        ROW_NUMBER() OVER (ORDER BY MIN(_Timestamp)) AS RowNum
    FROM Table1
    GROUP BY _Timestamp
)
SELECT
    t1.dt AS StartDate,
    t2.dt AS EndDate,
    DATEDIFF(MS, t1.dt, t2.dt) AS Elapsed
FROM Time_CTE t1
INNER JOIN Time_CTE t2
ON t2.RowNum = t1.RowNum + 1

将为您提供示例的以下输出:

StartDate               | EndDate                 | Elapsed
------------------------+-------------------------+--------
2009-12-20 11:59:56.000 | 2009-12-20 11:59:56.300 | 300
2009-12-20 11:59:56.300 | 2009-12-20 11:59:56.400 | 100
2009-12-20 11:59:56.400 | 2009-12-20 11:59:56.500 | 100
2009-12-20 11:59:56.500 | 2009-12-20 11:59:56.900 | 400

编辑:如果您想限制时间范围,只需在 GROUP BY 行之前添加 WHERE _Timestamp BETWEEN @StartDate AND @EndDate

Edit2:如果您想要平均值,则将最后的 SELECT t1.dt, ... 语句更改为:

SELECT AVG(DATEDIFF(MS, t1.dt, t2.dt))
FROM Time_CTE t1 ... (same as above)

【讨论】:

  • 谢谢,成功了!感谢大家的帮助...我学到了许多新的(对我而言)SQL 概念。我自己永远不会到达那里。
【解决方案2】:

第 1 步是只选择唯一的时间:

SELECT DISTINCT _TimeStamp FROM table 
    WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8';

然后,如果你想比较所有时间(不确定你想如何选择时间),你可以做一些疯狂的事情,比如:

SELECT t1._TimeStamp, t2._TimeStamp, DATEDIFF(ms,t1._TimeStamp,t2._TimeStamp) FROM 
    (SELECT DISTINCT _TimeStamp FROM table 
        WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8') AS t1 
    INNER JOIN
    (SELECT DISTINCT _TimeStamp FROM table 
        WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8') AS t2
WHERE t1._TimeStamp != t2._TimeStamp;

我的语法可能不正确,因为我来自 MySQL,但类似的东西应该可以工作。

如果你想要平均值,你可以尝试取上述结果的平均值:

SELECT AVG(DATEDIFF(ms,t1._TimeStamp,t2._TimeStamp)) FROM 
    (SELECT DISTINCT _TimeStamp FROM table 
        WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8') AS t1 
    INNER JOIN
    (SELECT DISTINCT _TimeStamp FROM table 
        WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8') AS t2
WHERE t1._TimeStamp != t2._TimeStamp;

仍然未经测试,但理论上,我认为它应该可以工作。

【讨论】:

  • ss 是秒,而不是毫秒 (ms)
  • 我在外部查询中搞砸了我的变量选择。我使用t1 而不是t1._TimeStamp。也许这就是问题所在。
  • 感谢您的所有帮助。如您所知,加入对我来说是新的,所以我很感激。
【解决方案3】:

如果我对你想要什么的假设是正确的,那么我看到了两种方法。

直接方式:

SELECT
    AVG(DATEDIFF(ms, T1.my_time, T2.my_time))
FROM
    My_Table T1
INNER JOIN My_Table T2 ON
    T2.my_time > T1.my_time
WHERE
    NOT EXISTS
    (
        SELECT
            *
        FROM
            My_Table T3
        WHERE
            (T3.my_time > T1.my_time AND T3.my_time < T2.my_time) OR
            (T3.my_time = T1.my_time AND T3.my_pk < T1.my_pk) OR
            (T3.my_time = T2.my_time AND T3.my_pk < T2.my_pk)
    )

棘手的方法:

SELECT
    DATEDIFF(ms, MIN(my_time), MAX(my_time))/(COUNT(DISTINCT my_time) - 1)
FROM
    My_Table

毕竟,平均差异只是总差异除以您将其分解为的分区数。

如果要限制日期范围,则需要为日期范围添加 WHERE 子句,并且需要考虑在第二个查询中除以零的可能性。

【讨论】:

    猜你喜欢
    • 2012-04-17
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 2018-08-01
    • 2019-02-21
    • 2017-06-24
    相关资源
    最近更新 更多