【问题标题】:Query to find last N events Type "2" occurred immediately before events Type "1"查询以查找最后 N 个事件类型“2”紧接在事件类型“1”之前发生
【发布时间】:2020-10-06 10:22:56
【问题描述】:

我有一长串从不同机器发送的事件(数百万)。

我需要获取在同一台机器中事件类型“1”之前发生的最后 N 个类型为“2”的事件

我找到了 N=1 的解决方案,但 我无法找到 N 个事件的解决方案

这是我对 N=1 的解决方案:

DECLARE @T AS TABLE
(
    [ID] [bigint] IDENTITY(1,1) NOT NULL,
    [CodeEvent] [int] NOT NULL,
    [DateTime] [datetime2](7) NULL,
    [Mach] [varchar](max) NULL
) 

INSERT @T VALUES
(2,'12:35:28','M2'),
(1,'12:35:21','M3'),
(4,'12:34:54','M3'),
(8,'12:34:35','M2'),
(2,'12:33:28','M2'),
(2,'12:33:21','M3'),
(1,'12:32:54','M1'),
(8,'12:32:35','M2'),
(1,'12:32:28','M2'),
(2,'12:32:25','M1'),
(1,'12:32:23','M3'),
(3,'12:32:21','M2'),
(2,'12:31:28','M2'),
(2,'12:31:21','M1'),
(4,'12:30:54','M3'),
(8,'12:30:35','M2'),
(1,'12:30:28','M2'),
(2,'12:30:25','M1'),
(2,'12:30:23','M3'),
(2,'12:30:21','M2'),
(1,'12:30:20','M3')

SELECT * FROM @T ORDER BY DateTime Desc;

WITH 
---- T1 All Events
T1 AS (SELECT TOP 100 * 
       FROM @T
       ORDER BY DateTime desc) 
,

---- T2 Events '1'
T2 AS (SELECT TOP 100 * 
       FROM T1 AS T
       WHERE (T.[CodeEvent] = 1)
       ORDER BY DateTime desc ) 
,

---- T4 Last Events type '2' Before type '1' same Mach
T4 AS   
    (select 
    T.ID,
    T.DateTime,
    T.[CodeEvent],
    T.[Mach],
    (SELECT  Top 1 T1.ID
        FROM T1 
        WHERE ((T1.Datetime < T.Datetime) 
           AND (T1.[Mach]=T.[Mach])
           AND (T1.CodeEvent=2))
        ORDER BY T1.DateTime desc) AS LAST_EVENT_ID
    FROM T2 AS T)
,
    
--- T6 get Event from ID
T6 AS (SELECT  
       T.[ID]
      ,T.[CodeEvent]
      ,T.[DateTime]
      ,T.[Mach]
       FROM T4 JOIN T1 AS T
       ON (T4.LAST_EVENT_ID = T.ID)) 


SELECT * FROM T2
UNION ALL
SELECT * FROM T6
ORDER BY [Mach],DateTime Desc

这是我在 N=1 时得到的

1   1900-01-01 12:32:54.0000000 M1
2   1900-01-01 12:32:25.0000000 M1

1   1900-01-01 12:32:28.0000000 M2
2   1900-01-01 12:31:28.0000000 M2

1   1900-01-01 12:30:28.0000000 M2
2   1900-01-01 12:30:21.0000000 M2

1   1900-01-01 12:35:21.0000000 M3
2   1900-01-01 12:33:21.0000000 M3

1   1900-01-01 12:32:23.0000000 M3
2   1900-01-01 12:30:23.0000000 M3

这是我想在 N=2 时获得的

1   1900-01-01 12:32:54.0000000 M1
2   1900-01-01 12:32:25.0000000 M1
2   1900-01-01 12:31:21.0000000 M1

1   1900-01-01 12:32:28.0000000 M2
2   1900-01-01 12:31:28.0000000 M2
2   1900-01-01 12:30:33.0000000 M2

1   1900-01-01 12:35:21.0000000 M3
2   1900-01-01 12:33:21.0000000 M3
2   1900-01-01 12:30:23.0000000 M3

【问题讨论】:

  • 请用您正在运行的数据库标记您的问题:oracle、sql-server、postgresql...?

标签: sql date window-functions gaps-and-islands


【解决方案1】:

我理解为差距和孤岛问题。对于每台机器,您希望保留所有“1”个事件和 N 个前面的“2”个事件。

一种方法是定义组,其窗口总和随每个“1”事件递增。然后,您可以使用row_number() 枚举组内的记录,并进行过滤。

这回答了 N = 2 的问题。

select CodeEvent, DateTime, Mech
from (
    select
        t.*,
        row_number() over(partition by Mach, grp order by DateTime desc) rn
    from (
        select 
            t.*,
            sum(case when CodeEvent = 1 then 1 else 0 end) over(partition by Mach order by DateTime desc) grp
        from @T t
        where CodeEvent in (1, 2)   
    ) t
) t
where rn <= 3
order by DateTime

您可以通过调整 rn 上的最终过滤器来控制 N。

【讨论】:

    猜你喜欢
    • 2021-08-20
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 2017-05-09
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多