SQL-Server-2017:使用时间戳标准自行加入 table

SQL-Server-2017: Self join a table using timestamp criteria

我有一个名为 events 的 table,看起来像这样:

            timestamp      | intvalue | hostname | attributes
    2019-03-13 14:43:05.437|    257   |  room04  | Success 000
    2019-03-13 14:43:05.317|    257   |  room03  | Success 000
    2019-03-13 14:43:03.450|   2049   |  room05  | Error 108
    2019-03-13 14:43:03.393|     0    |  room05  | TicketNumber=3
    2019-03-13 14:43:02.347|     0    |  room04  | TicketNumber=2
    2019-03-13 14:43:02.257|     0    |  room03  | TicketNumber=1

上面是 table 的示例,其中包含数千行这样的内容。 我将用几句话解释您在 table 中看到的内容。 timestamp 列给出了每个事件发生的日期和时间。在intvalue列中,257表示成功进入,2049表示错误,0表示有工单请求。 hostname 给出了读取每张票的 card/ticket reader 的名称,attributes 列给出了一些细节,比如票号(1、2、3 等)或错误类型(即 108 或 109)以及事件是否成功。

在这种情况下有一个模式说,如果一张票请求进入并且它是有效的并且发生在像14:43:02.257这样的时间,那么成功进入的消息将被写入数据库(作为一个新事件)在 6 秒内 至多 (即最大 14:49:02.257)后,票被 reader.

如果门票未能进入,则在 100 毫秒的时间间隔后,错误消息将写入数据库。

所以在这个例子中,我想做的是创建一个 table 如下所示

        timestamp      | intvalue | hostname |   result    |  ticketnumber
2019-03-13 14:43:05.437|    257   |  room04  | Success 000 | TicketNumber=2
2019-03-13 14:43:05.317|    257   |  room03  | Success 000 | TicketNumber=1
2019-03-13 14:43:03.450|   2049   |  room05  |  Error 108  | TicketNumber=3

如您所见,带有 TicketNumber=3 的票与结果 Error 108 匹配,因为如果您查看初始的 table,它们的时间间隔小于 100 毫秒,另外两张票与各自的结果一对一匹配,因为时间间隔小于 6 秒(超过 100 毫秒)。您还可以注意到,主机名可以帮助匹配,具有 TicketNumber=3 属性的行具有 room05hostname,就像具有 room05 属性的下一行一样=24=].

我一直在尝试自行加入此 table 或通过 CTE 加入。我使用过交叉应用,我也尝试过使用 datediff 的方法,但我失败得很惨,我被卡住了。 有没有人可以帮助我并向我展示实现预期结果的正确方法? 非常感谢您的宝贵时间。

好的...根据您提供的数据,这是您要求的结果。这只是一个示例,说明如何编写自联接以获取示例中的结果。我希望这会把你推向正确的方向。

IF OBJECT_ID('tempdb..#t') IS NOT NULL
BEGIN
    DROP TABLE #t
END
CREATE TABLE #t
(
    [timestamp] DATETIME,
    intValue INT,
    hostName VARCHAR(50),
    attributes VARCHAR(50)
)
INSERT INTO #t([timestamp], intValue, hostName, attributes)
VALUES  ('2019-03-13 14:43:05.437', 257, 'room04', 'Success 000'),
        ('2019-03-13 14:43:05.317',257, 'room03','Success 000'),
        ('2019-03-13 14:43:03.450',2049, 'room05','Error 108'),
        ('2019-03-13 14:43:03.393',0, 'room05','TicketNumber=3'),
        ('2019-03-13 14:43:02.347',0, 'room04','TicketNumber=2'),
        ('2019-03-13 14:43:02.257',0, 'room03','TicketNumber=1')

SELECT x.[timestamp], x.intValue, x.hostName, x.attributes result, y.attributes 
ticketnumber
FROM (SELECT * FROM #t WHERE intValue > 0) AS x 
INNER JOIN #t y
ON x.hostName = y.hostName AND y.intValue = 0
GROUP BY x.[timestamp], x.intValue, x.hostName, x.attributes, y.attributes
ORDER BY x.[timestamp] DESC

我不会尝试将它复制到您的项目中并使用它,这只是一个如何使用连接的示例。在发布一个完整的解决方案之前,我需要更多关于你想要完成什么的信息,因为有更好的方法来为大型数据集生成报告。 - 比尔

由于您使用的是 SQL 2017,因此您可以使用 lead/lag。

with evt(timestamp,intvalue,hostname,attributes) as 
(

    select cast('2019-03-13 14:43:05.437' as datetime),   257 , 'room04','Success 000' union all
    select cast('2019-03-13 14:43:05.317' as datetime),   257 , 'room03','Success 000' union all
    select cast('2019-03-13 14:43:03.450' as datetime),  2049 , 'room05','Error 108' union all
    select cast('2019-03-13 14:43:03.393' as datetime),    0  , 'room05','TicketNumber=3' union all
    select cast('2019-03-13 14:43:02.347' as datetime),    0  , 'room04','TicketNumber=2' union all
    select cast('2019-03-13 14:43:02.257' as datetime),    0  , 'room03','TicketNumber=1'
    )
select [timestamp], intvalue, hostname, attributes, lag(attributes) over (partition by hostname order by timestamp) ticketnumber, datediff(ss,lag([timestamp]) over (partition by hostname order by timestamp), [timestamp]) lapse
from evt
order by timestamp

时间延迟似乎并没有真正产生影响,除非以某种方式可以在一个房间中交错显示成功和失败消息。假设两个请求不会在没有中间事件的情况下连续发生,那么您可以使用 lag():

select e.*
from (select timestamp, intvalue, hostname, attributes,
             lag(attributes) over (partition by hostname order by timestamp) as ticketnumber
      from event
     ) e
where intvalue > 0
order by timestamp