【问题标题】:SQL-Server-2017: Self join a table using timestamp criteriaSQL-Server-2017:使用时间戳标准自联接表
【发布时间】:2019-03-13 20:15:10
【问题描述】:

我有一个名为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,其他两张票是1-to-匹配的1 与他们各自的结果,因为时间余量小于 6 秒(超过 100 毫秒)。您还可以注意到,主机名可以帮助匹配,具有TicketNumber=3 属性的行具有room05hostname,就像具有Error 108 属性的下一行一样。

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

【问题讨论】:

  • 请发布您最成功的尝试以及您得到的结果。

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


【解决方案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

【讨论】:

  • 是的,你是对的!这做得很好。确实,时间滞后没有任何区别。谢谢你帮助我!
【解决方案2】:

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

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

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

【讨论】:

  • 非常感谢您的回答,对您有很大帮助!你知道,它把我带到了一个好地方,但问题是我需要使用我上面写的时间标准。例如,我需要将票号与数据库中的第一个结果相匹配,该结果在前 6 秒的最大时间间隔内,到票号被写入数据库时​​。对于这种情况,我会踩到您的脚本,并且还选择 x.timestamp 和 y.timestamp 之间的时间差。然后我添加一个 where 子句,说明这两个时间戳之间的差异必须是
  • 我现在的状态肯定比以前好,我会进步的。如果我选择正确,我会将您的答案标记为正确。非常感谢您的时间和支持。
【解决方案3】:

由于您使用的是 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

【讨论】:

  • 感谢您的回答!这似乎是一个非常好的主意,我会检查结果是否正确,如有必要,我会进行修改,我会通知您。
猜你喜欢
  • 1970-01-01
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 2017-05-29
  • 2017-04-30
  • 1970-01-01
相关资源
最近更新 更多