SQL-Server-2017:使用时间戳条件自连接表

时间:2019-03-13 20:15:10

标签: sql sql-server join common-table-expression sql-server-2017

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

            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

上面是一个包含数千行的表格示例。 我将用几句话来解释您在此表中看到的内容。 timestamp列提供每个事件发生的日期和时间。在intvalue列中,257表示输入成功,2049表示错误,0表示发出请求的票证。 hostname提供了读取每张票证的读卡器/票证读取器的名称,而attributes列提供了一些详细信息,例如票证的编号(1、2、3等)或错误的类型(例如108或109),以及事件是否成功。

在这种情况下,有一种模式表示,如果票证要求进入并且该票证有效且发生在14:43:02.257之类的时间,则成功进入的消息将被写入数据库(如一个新事件)在票证读取器读取票证后最多6秒内(最多14:49:02.257)。

如果票证无法进入,则在100毫秒的时间间隔内,错误消息将被写入数据库。

所以在这个示例中,我要做的是创建一个如下表

        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匹配,因为如果您查看初始表,它们的时间裕度小于100ms,则其他两张票证将匹配一对一的结果,因为时间余量少于6秒(且超过100ms)。您还可以注意到,主机名可以帮助进行匹配,属性为TicketNumber=3的行的hostnameroom05,就像下一行属性为{ {1}}。

我一直试图自行加入该表或将其与CTE结合。我使用了交叉应用,也尝试过使用Error 108的方法,但是我失败了,我陷入了困境。 有没有人可以帮助我并向我展示实现预期结果的正确方法? 非常感谢您的宝贵时间。

3 个答案:

答案 0 :(得分:1)

确定...这是根据您提供的数据要求的结果。这只是如何编写自我联接以获取示例中结果的示例。我希望这能将您推向正确的方向。

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

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

答案 1 :(得分:1)

由于使用的是SQL 2017,因此可以使用超前/滞后。

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

答案 2 :(得分:1)

时间延迟似乎并没有真正改变,除非以某种方式可以将单个房间与成功和失败消息交织在一起。假设在没有介入事件的情况下没有连续发生两个请求,那么可以使用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