2012-05-23 126 views
1

我正在使用MSSQL 2008标准版计算sql中两行两次之间的差异

我在选择命令中有多行填充事件。对于每一个我有一个时间戳的事件,我现在要计算事件之间的时间:

(number) | event   | timestamp   | duration 
---------+----------------+---------------------+---------- 
1  | logon   | 2012-05-23 10:00:00 | 
2  | incomming call | 2012-05-23 10:01:00 | 
3  | call ended  | 2012-05-23 10:02:00 | 
4  | logoff   | 2012-05-23 10:04:00 | 

(数列不存在,但它的解释更容易),现在的时间单元第一行应为1,第二行也为1,第三行为2.

有没有人知道如何实现这个没有循环等。

谢谢

+0

你确定你的意思是'MSSQL 2010'?没有我知道的这样的版本。 –

+0

对不起,2008当然是:-) – Philipp

回答

1

我发现比提供不太理想的CTE答案。我发现其他答案与联合太复杂。我把这个问题解释成这个片段

这里是使用CTE的代码,在CTE的select中创建一个序列,它通过一个有序的时间戳标识一个行号。生成的选择选取生成的有序行并确定分钟。

WITH AgentActions AS 
(
    select ROW_NUMBER() OVER (ORDER BY [TimeStamp]) -- Create an index number ordered by time. 
     AS [Sequence], 
    * from AgentInteractions 
) 
SELECT *, 
     ISNULL(DATEDIFF(Minute, 
         (SELECT other.TimeStamp 
           FROM AgentActions Other 
           WHERE other.Sequence = AgentActions.Sequence - 1), 
         AgentActions.TimeStamp), 
       0) 
    AS MinutesFromLastPoint 
FROM AgentActions; 

下面是设置表

CREATE TABLE AgentInteractions 
(
[Event]  VARCHAR(12) NOT NULL, 
[Timestamp] [DateTime] NOT NULL 
); 

INSERT INTO dbo.AgentInteractions(Event, TimeStamp ) 
VALUES ('Alpha', '1-Jan-2018 3:04:22 PM'), 
     ('Omega', '3-Jan-2018 10:04:22 PM'), 
     ('Beta', '2-Jan-2018 2:04:22 AM'); 

结果

enter image description here

SQL Fiddle Example

+0

谢谢你的回答,它的确看起来很好。我想知道为什么你要用子查询来计算时间戳的差异,而不是像我自己的解决方案那样加入连接。我比较了它,估计的执行计划表示加入的版本是41%,子查询是批量的59%。 – Philipp

+0

@Philipp有趣的结果...这是很好的记住。 – OmegaMan

+0

我会将您的答案设置为解决方案,但是最终的连接将需要更改...(作为可能需要其他人的信息) – Philipp

3

您需要自行加入。既然你需要生成一个ID,然后是这样的:

select t1.*, datediff(minute, t2.timestamp, t1.timestamp) from 
    (select *, row_number() over (order by ...) as rowid from MyTable) t1 
inner join 
    (select *, row_number() over (order by ...) as rowid from MyTable) t2 
on t1.rowid = t2.rowid - 1 
+0

我需要改变一下这个问题:目前没有id列,这只是一个数字列,使它更容易,你知道一种方法可能创建它它的选择?这些事件不在同一个工会的两个表中 – Philipp

+0

您可以将结果放入临时表中,该表具有自动生成的ID列,然后自行加入。你也可以看看在(...)上使用row_number()。 – Phil

+0

@PhilippMehrwald:更新的答案 – Phil

1

这是我目前的版本/解决方案:

declare @temp table 
(
    id int, 
    timestamp datetime, 
    type nvarchar(255), 
    skillname nvarchar(255), 
    event nvarchar(255), 
    userstatus nvarchar(255) 
) 

insert into @temp (id, timestamp, type, skillname, event, userstatus) 
(
    select ROW_NUMBER() over (order by timestamp) as id, * from 
    (
     select TimeStamp, 'Event' as type, SkillName, Event, UserStatus from AgentEvents 
      where TimeStamp >= '2012-05-22T00:00:00' 
       and UserName like '%engel%' 
     union 
     select TimeStamp, 'Anruf' as type, SkillName, '' as event, '' as status from calls 
      where TimeStamp >= '2012-05-22T00:00:00' 
       and UserName like '%engel%' 
    ) as a 
) 

select t1.*, DATEDIFF(second, t1.timestamp, t2.timestamp) as duration 
from @temp t1 
left outer join @temp t2 on t1.id = t2.id - 1 

编辑:改变inner joinleft outer join,否则最后一行会丢失。

0

据我所知,你需要更新持续时间栏。

您可以使用这样的事情:

update mytable a set duration = DateDiff(a.timestamp, select top b.timestamp from mytable b order by b.timestamp asc) 

我不能测试,但只给你一个想法(它可能有一些语法错误)。 使用'top'和'order by'子句应该可以做到这一点。

(编辑)

+0

select top将只适用于SQLServer而不是其他任何数据库 – richardtz

0

我想你最好,因为它不报告的第一行创建触发器

CREATE TRIGGER update_duration ON sometable 
INSTEAD OF INSERT 
AS 
DECLARE @lastDT datetime 
BEGIN 
SET @lastDT = 
    (SELECT TOP 1 _timestamp 
    FROM sometable 
    ORDER BY _timestamp DESC) 
UPDATE sometable 
SET duration = DATEDIFF(MINUTE, @lastDT, GETDATE()) 
END 
+0

我使用'union'将2个表放在一起,触发器无法选择。 – Philipp

0

WITH rows AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY Col1) AS rn FROM dbo.Table_2 ) SELECT mc.col1, DATEDIFF(HOUR, mc.Col1, mp.Col1) as TimeDiffInHours FROM rows mc JOIN rows mp ON mc.rn = mp.rn-1

+0

由于'mc.rn = mp.rn-1',导致数据不报告第一行,它不能匹配第1行。 – OmegaMan