【问题标题】:Calculate time duration between differents records in a table based on datetimes根据日期时间计算表中不同记录之间的持续时间
【发布时间】:2012-06-11 13:21:09
【问题描述】:

对于这个问题,假设我有一个包含以下数据的表:

1) 名称 2) 心情 3) 日期时间

我可以插入如下记录:

Andy    Happy    '11.06.2012 - 14.06.07' -- Inserted on 11.06.2012 @ 19:12.32
Arthur  Angry    '11.06.2012 - 15.06.57' -- Inserted on 11.06.2012 @ 17:12.32
Andy    Sad      '11.06.2012 - 14.34.05' -- Inserted on 11.06.2012 @ 17:12.32
Arthur  Happy    '11.06.2012 - 13.34.05' -- Inserted on 11.06.2012 @ 14:12.32

我想获取与这些情绪变化相关的“持续时间”信息!

我的表包含数千条记录,我无法承受需要花费太多时间的过程。计算这个的最佳方法是什么?

  • 触发“插入后”,填充“持续时间”列?
  • 填充先前创建的“持续时间”列的存储过程?
  • 计算列?
  • 一个视图(我已经试过了,显示时间超过 2 秒,完全不能接受)
  • 另一个想法?

感谢您的帮助!

重要编辑: 情绪记录分组到数据包中,我们不能确定已经插入的记录有更小的日期! (见我记录旁边的上述cmets)

【问题讨论】:

  • 如何使用数据透视查询将数据放入同一行,然后将该查询用作子查询,然后您可以在其中进行数学运算。
  • 您可以将心情开始时间和心情结束时间作为单独的列吗?如果是,那么您可以使用 TO_CHAR() 函数来查找差异。
  • 你也可以在视图上放置索引(虽然它们有一些很大的限制)
  • 不要使用触发器。为什么需要存储可以在查询时派生的冗余数据?如果你真的认为你需要存储它,为什么不添加增量作为插入新行的一部分(它所要做的就是为同一用户获取现有的 MAX([datetime]) )?
  • @Limey 你将如何构建一个索引视图来更快地回答这个查询?

标签: sql-server view calculated-columns


【解决方案1】:

可能的 SQL 版本:

WITH CTE AS(
    SELECT ROW_NUMBER()OVER(PARTITION BY [Name] ORDER BY [Time])As RowNum
    , *
    FROM @table T
)
SELECT 
    DiffSec=DATEDIFF(s,[Time],(SELECT [Time] FROM CTE c2 WHERE c2.[Name]=CTE.[Name] AND c2.RowNum=CTE.RowNum+1))
    , [Name]
    , Mood
    , [Time]
FROM CTE 
ORDER BY [Name],[RowNum]

结果:

DiffSec Name    Mood    Time
1678    Andy    Happy   2012-06-11 14:06:07.000
NULL    Andy    Sad     2012-06-11 14:34:05.000
5228    Arthur  Angry   2012-06-11 14:06:57.000
NULL    Arthur  Happy   2012-06-11 15:34:05.000

您的测试数据:

declare @table table(name varchar(10),mood varchar(10),time datetime);
insert into @table values('Andy','Happy',convert(datetime,'11.06.2012 14:06:07',104));
insert into @table values('Arthur','Angry',convert(datetime,'11.06.2012 14:06:57',104));
insert into @table values('Andy','Sad',convert(datetime,'11.06.2012 14:34:05',104));
insert into @table values('Arthur','Happy',convert(datetime,'11.06.2012 15:34:05',104));

编辑自加入CTE 似乎是一个非常糟糕的主意(If you self join the CTE it will kill you)。我用临时表中的 500000 条记录测试了我的查询,并在 30 分钟后取消了查询。

这是使用子查询(使用您的注释架构)的更快方法(总共 4 秒):

SELECT T.*
    ,(SELECT DATEDIFF(s,MAX(T2.Time),T.Time)
      FROM dbo.Temp T2
      WHERE T2.HE_Id = T.HE_Id
          AND T2.Time < T.Time
    ) AS DiffSec
FROM dbo.Temp AS T
ORDER BY HE_Id ,DiffSec

【讨论】:

  • 在 Denali / SQL 2012 中,您现在拥有带分区的 LEAD() 和 LAG()。
  • @AndyM:50 万条记录相对较少。你有proper indices 在你的桌子上吗?您是存储用户名还是仅存储外键(推荐)?
  • @AndyM:尝试在您的表上创建此索引或类似索引:CREATE INDEX idxNameTime ON YourTable([Name], [Time]);
  • @AndyM:名称和情绪字段是什么?
  • @AndyM:“如果你自己加入 CTE,它会杀了你” ;-) 编辑了我的答案以提供另一种方法。
猜你喜欢
  • 2020-06-28
  • 2014-02-28
  • 2016-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多