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
属性的行具有 room05
的 hostname
,就像具有 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
我有一个名为 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
属性的行具有 room05
的 hostname
,就像具有 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