【问题标题】:SQL Server DATEDIFF Computed Column Between RowsSQL Server DATEDIFF 计算列之间的行
【发布时间】:2016-09-16 10:19:38
【问题描述】:

我目前有一张类似的表-

RecordTime                    Running     Fault
-----------------------------------------------
2016-09-15 11:32:01.00        0           202
2016-09-15 11:32:08.00        1           202
2016-09-15 11:39:31.00        0           21
2016-09-15 11:40:07.00        1           4
2016-09-15 11:42:11.00        0           21
2016-09-15 11:42:39.00        1           45

然后我想计算每条记录的 RecordTimes 之间的时间差。为此,我使用以下 -

WITH    rows AS
        (
        SELECT  *, ROW_NUMBER() OVER (ORDER BY RecordTime) AS rn
        FROM    dbo.Table1
        )
SELECT  DATEDIFF(second, mc.RecordTime, mp.RecordTime)
FROM    rows mc
JOIN    rows mp
ON      mc.rn = mp.rn - 1

返回 -

(No column name)
----------------
7
443
36
124
28
303

不过,我真正想做的是在原始表中创建一个计算列,以提供这些值。这可能吗?

我认为我可以将查询转换为 UDF,然后在列中引用它,但我对这种工作不是很有经验。

---编辑---

最终结果应该是-

RecordTime                    Running     Fault     Diff
--------------------------------------------------------
2016-09-15 11:32:01.00        0           202       7
2016-09-15 11:32:08.00        1           202       443
2016-09-15 11:39:31.00        0           21        36
2016-09-15 11:40:07.00        1           4         124
2016-09-15 11:42:11.00        0           21        28
2016-09-15 11:42:39.00        1           45        303

【问题讨论】:

  • 显示你的最终结果应该是..
  • 您使用的是哪个版本的 SQL Server?
  • 2012...对不起,应该说
  • 它会影响性能,最好在运行中获得它
  • 在飞行中?你是什​​么意思?另外,抱歉耽搁了,我正在处理答案...

标签: sql sql-server tsql sql-server-2012


【解决方案1】:

我建议您为此目的使用视图:

CREATE VIEW Table1_vw 
AS
WITH cte AS (
    SELECT  *, 
            ROW_NUMBER() OVER (ORDER BY RecordTime) AS rn
    FROM    dbo.Table1
)
SELECT  mc.RecordTime,
        mc.Running,
        mc.Fault,
        DATEDIFF(second, mc.RecordTime, mp.RecordTime) Diff
FROM cte mc
LEFT JOIN cte mp
ON mc.rn = mp.rn - 1

由于您使用的是SQL Server 2012,您可以使用LEAD 函数:

CREATE VIEW Table1_vw 
AS
SELECT  RecordTime,
        Running,
        Fault,
        DATEDIFF(second,RecordTime,LEAD(RecordTime,1,NULL) OVER (ORDER BY RecordTime ASC) ) as Diff
FROM Table1
GO

【讨论】:

  • 嘿@gofr1,这是一个非常明确的答案(并且有效!)。但是你能解释一下为什么创建视图更好吗?它比 UDF 和计算列更有效吗?
  • @swe 好吧,这并不是什么新鲜事 :) 花一些时间阅读文章和博客,如(SQL authoritySQLServerCentral 等),并在 SO 上阅读答案/问题!
  • 感谢@gofr1 的回答。我将开始更多地考虑使用视图而不是添加计算列。至少写起来肯定更容易。
  • @Jamsandwich 很抱歉延迟了 cmets。根据我在计算列(甚至视图内部)中使用 UDF 的经验,可能会导致严重的性能问题。但是,如果您的表不会显着增长并且插入/更新率不会那么大 - 您可以毫无问题地使用 UDF。
  • @gofr1 没关系。我的桌子现在很小,但随着时间的推移它们可能会增长。我每 10 分钟为每个表插入/更新一次。不知道这与规范相比如何,但为了安全起见,我会提出观点。这听起来也是一种思考操作的有用方式,尤其是因为它似乎更容易编码!
【解决方案2】:

怎么样:

CREATE FUNCTION GetTimeDiff (@time datetime)
RETURNS INT 
AS BEGIN
    declare @t1 datetime 

    DECLARE @Ret int

    SELECT @t1 = RecordTime 
    FROM (
        SELECT  RecordTime, 
                ROW_NUMBER() OVER (ORDER BY RecordTime DESC) AS rn
        FROM Table1
        WHERE RecordTime < @time
    ) i
    WHERE i.rn = 1

    SELECT @Ret = DATEDIFF(second, @t1, @time)
    RETURN @Ret
END
GO

ALTER TABLE Table1
ADD TimeDiff AS dbo.GetTimeDiff(RecordTime) 
GO

您需要在函数中添加逻辑来处理 NULL @t1 等。

更新以使其适用于下一行:

 ROW_NUMBER() OVER (ORDER BY RecordTime ASC) AS rn
        FROM Table1
        WHERE RecordTime > @time

这让所有的价值观都是积极的而不是消极的:

SELECT @Ret = ABS(DATEDIFF(second, @t1, @time))

【讨论】:

  • 我遇到了一些错误。第 12 行 - “函数中的选择语句不能将数据返回给客户端”和“函数中的最后一条语句必须是返回语句”。
  • 嘿,artm。此功能现在有效。但 TimeDiff 出现偏移 1 行。所以第一行显示空值,然后计算与前一行的差异。是否可以计算与下一行的差异?
  • 太棒了。这样可行。在我将 ABS 函数添加到最终选择之前,一直在获取负值。您对按照 Gofr1 的建议使用此视图有何看法?
  • @Jamsandwich 我只是想回答问题的计算列部分,但我认为 Gofr1 的答案 (+1) 是一个更好的选择。
  • 好的,太好了。那我就看风景了。但是+1,向我展示了如何将其作为计算列来完成。很高兴看到我可以将自己的数据与之关联的 UDF 示例。
猜你喜欢
  • 2015-02-10
  • 1970-01-01
  • 1970-01-01
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
相关资源
最近更新 更多