mysql - 通过比较前后记录创建自定义 session 标识符

标签 mysql sql-server teradata amazon-redshift vertica

我正在尝试基于数据创建一些 session (在 Vertica 中,但任何其他 OLAP 数据库 SQL 都应该有效)

我有一个简单的表,包含名为 Vehicle-ID、Event、Event-Code 的列,“Session-ID”是我要填充的列

我尝试过分区、领先、滞后和其他分析功能,但没有成功。 session的创建逻辑如下。

session 在您第一次遇到启动事件 ( 1 ) 时开始,并在获得最后一个停止 (2) 事件时结束。正如您在 session 开始后在 session 中看到的那样,如果我们得到更多的开始事件,我们将忽略并寻找最后停止事件。示例 Session-Id-1

由于某种原因,在停止事件之后,下一个事件没有开始(即运行等),这意味着它是一个糟糕的 session ,我们想要捕获这个糟糕的 session ,直到我们找到一个新的开始。例子在session-id-2

我正在尝试使用 lead 和 lag 创建标记,它们查看前后的记录,并添加标记,如 first_start、final_end 等 .. 但它变得笨拙

更新 SQL 查询以创建 session

SELECT * , SUM(FLAG) OVER ( PARTITION BY Vehicle_ID ORDER BY Event_Time ROWS UNBOUNDED PRECEDING) AS SESSION_ID
FROM (
    SELECT * ,
    Case when Prev_Start_time < Prev_Stop_time and Event != 'Started' Then 1 else 0 end as bad_data ,
    Case when 
        ( Event = 'Started' and Prev_Start_time < Prev_Stop_time ) OR 
        --( Event = 'Stopped' and Prev_Event = 'Stopped' ) OR 
        ( Event = 'Running' and Prev_Start_time < Prev_Stop_time) OR 
        ( Prev_Event IS NULL) 
    THEN 1 END AS FLAG
    --Case when ( Event = 'Stopped' and Next_Event = 'Stopped' ) OR ( Event != 'Started' and Prev_Start_time < Prev_Stop_time) OR ( Prev_Event IS NULL) THEN 1 END AS FLAG
    FROM (
    WITH
        input(Vehicle_ID,Event_time,Event,Event_Code) AS (
                  SELECT 1,TIME '09:01:00','Started',1
        UNION ALL SELECT 1,TIME '09:02:00','Started',1
        UNION ALL SELECT 1,TIME '09:03:00','Running',3
        UNION ALL SELECT 1,TIME '09:04:00','Started',1
        UNION ALL SELECT 1,TIME '09:05:00','Running',3
        UNION ALL SELECT 1,TIME '09:06:00','Running',3
        UNION ALL SELECT 1,TIME '09:07:00','Running',3
        UNION ALL SELECT 1,TIME '09:08:00','Stopped',2
        UNION ALL SELECT 1,TIME '09:09:00','Stopped',2
        UNION ALL SELECT 1,TIME '09:10:00','Running',3
        UNION ALL SELECT 1,TIME '09:11:00','Running',3
        UNION ALL SELECT 1,TIME '09:12:00','Running',3
        UNION ALL SELECT 1,TIME '09:13:00','Started',1
        UNION ALL SELECT 1,TIME '09:14:00','Started',1
        UNION ALL SELECT 1,TIME '09:15:00','Running',3
        UNION ALL SELECT 1,TIME '09:16:00','Started',1
        UNION ALL SELECT 1,TIME '09:17:00','Running',3
        UNION ALL SELECT 1,TIME '09:18:00','Running',3
        UNION ALL SELECT 1,TIME '09:19:00','Running',3
        UNION ALL SELECT 1,TIME '09:20:00','Stopped',2
        UNION ALL SELECT 1,TIME '09:21:00','Started',1
        UNION ALL SELECT 1,TIME '09:22:00','Started',1
        UNION ALL SELECT 1,TIME '09:23:00','Running',3
        UNION ALL SELECT 1,TIME '09:24:00','Started',1
        UNION ALL SELECT 1,TIME '09:25:00','Running',3
        UNION ALL SELECT 1,TIME '09:26:00','Running',3
        UNION ALL SELECT 1,TIME '09:27:00','Running',3
        UNION ALL SELECT 1,TIME '09:28:00','Stopped',2
        )
    SELECT *, 
    Max( Case Event when 'Started' then Event_time end ) OVER (PARTITION BY Vehicle_ID ORDER BY Event_time Rows between unbounded preceding and 1 preceding ) AS Prev_Start_time,
    Max( Case Event when 'Stopped' then Event_time end ) OVER (PARTITION BY Vehicle_ID ORDER BY Event_time Rows between unbounded preceding and 1 preceding ) AS Prev_Stop_time,
    LAG(Event) OVER (PARTITION BY Vehicle_ID ORDER BY Event_time ) AS Prev_Event,
    LEAD(Event) OVER (PARTITION BY Vehicle_ID ORDER BY Event_time ) AS Next_Event
    FROM input ) AS T1
) AS T2 

根据更新的查询新输入

Vehicle_ID  Event_time      Event       Event_Code  Prev_Start_time Prev_Stop_time      Prev_Event      Next_Event      bad_data    FLAG        SESSION_ID
1           9:01:00         Started         1           NULL            NULL            NULL            Started         0           1           1
1           9:02:00         Started         1           9:01:00         NULL            Started         Running         0           NULL            1
1           9:03:00         Running         3           9:02:00         NULL            Started         Started         0           NULL            1
1           9:04:00         Started         1           9:02:00         NULL            Running         Running         0           NULL            1
1           9:05:00         Running         3           9:04:00         NULL            Started         Running         0           NULL            1
1           9:06:00         Running         3           9:04:00         NULL            Running         Running         0           NULL            1
1           9:07:00         Running         3           9:04:00         NULL            Running         Stopped         0           NULL            1
1           9:08:00         Stopped         2           9:04:00         NULL            Running         Stopped         0           NULL            1
1           9:09:00         Stopped         2           9:04:00         9:08:00         Stopped         Running         1           NULL            1
1           9:10:00         Running         3           9:04:00         9:09:00         Stopped         Running         1           1           2
1           9:11:00         Running         3           9:04:00         9:09:00         Running         Running         1           1           3
1           9:12:00         Running         3           9:04:00         9:09:00         Running         Started         1           1           4
1           9:13:00         Started         1           9:04:00         9:09:00         Running         Started         0           1           5
1           9:14:00         Started         1           9:13:00         9:09:00         Started         Running         0           NULL            5
1           9:15:00         Running         3           9:14:00         9:09:00         Started         Started         0           NULL            5
1           9:16:00         Started         1           9:14:00         9:09:00         Running         Running         0           NULL            5
1           9:17:00         Running         3           9:16:00         9:09:00         Started         Running         0           NULL            5
1           9:18:00         Running         3           9:16:00         9:09:00         Running         Running         0           NULL            5
1           9:19:00         Running         3           9:16:00         9:09:00         Running         Stopped         0           NULL            5
1           9:20:00         Stopped         2           9:16:00         9:09:00         Running         Started         0           NULL            5
1           9:21:00         Started         1           9:16:00         9:20:00         Stopped         Started         0           1           6
1           9:22:00         Started         1           9:21:00         9:20:00         Started         Running         0           NULL            6
1           9:23:00         Running         3           9:22:00         9:20:00         Started         Started         0           NULL            6
1           9:24:00         Started         1           9:22:00         9:20:00         Running         Running         0           NULL            6
1           9:25:00         Running         3           9:24:00         9:20:00         Started         Running         0           NULL            6
1           9:26:00         Running         3           9:24:00         9:20:00         Running         Running         0           NULL            6
1           9:27:00         Running         3           9:24:00         9:20:00         Running         Stopped         0           NULL            6
1           9:28:00         Stopped         2           9:24:00         9:20:00         Running         NULL            0           NULL            6

最佳答案

在 Vertica 中,我会使用 MATCH() 子句。它还会遗漏不需要的行 - 那些没有意义的“运行”。 试试这个:

    WITH
    -- your input as you gave it 
    input(tm,Vehicle_ID,Col1,Event,Event_Code,Session_ID) AS (
              SELECT TIME '09:01:00',1,'A','Started',1,1
    UNION ALL SELECT TIME '09:02:00',1,'B','Started',1,1
    UNION ALL SELECT TIME '09:03:00',1,'C','Running',3,1
    UNION ALL SELECT TIME '09:04:00',1,'A','Started',1,1
    UNION ALL SELECT TIME '09:05:00',1,'B','Running',3,1
    UNION ALL SELECT TIME '09:06:00',1,'C','Running',3,1
    UNION ALL SELECT TIME '09:07:00',1,'A','Running',3,1
    UNION ALL SELECT TIME '09:08:00',1,'A','Stopped',2,1
    UNION ALL SELECT TIME '09:09:00',1,'B','Stopped',2,1
    UNION ALL SELECT TIME '09:10:00',1,'C','Running',3,2
    UNION ALL SELECT TIME '09:11:00',1,'A','Running',3,2
    UNION ALL SELECT TIME '09:12:00',1,'B','Running',3,2
    UNION ALL SELECT TIME '09:13:00',1,'A','Started',1,3
    UNION ALL SELECT TIME '09:14:00',1,'B','Started',1,3
    UNION ALL SELECT TIME '09:15:00',1,'C','Running',3,3
    UNION ALL SELECT TIME '09:16:00',1,'A','Started',1,3
    UNION ALL SELECT TIME '09:17:00',1,'B','Running',3,3
    UNION ALL SELECT TIME '09:18:00',1,'C','Running',3,3
    UNION ALL SELECT TIME '09:19:00',1,'A','Running',3,3
    UNION ALL SELECT TIME '09:20:00',1,'A','Stopped',2,3
    )
    -- here is where the real select starts ..
    SELECT
      pattern_id()
    , match_id()
    , event_name()
    , *
    FROM input
    MATCH(
      PARTITION BY vehicle_id
      ORDER BY tm
      DEFINE
        started_event AS (event='Started')
      , running_event AS (event='Running')
      , stopped_event AS (event='Stopped')
      PATTERN p AS (started_event+ (running_event|started_event)* stopped_event+)
    )
    ;


    pattern_id|match_id|event_name   |tm      |Vehicle_ID|Col1|Event  |Event_Code|Session_ID
             1|       1|started_event|09:01:00|         1|A   |Started|         1|         1
             1|       2|started_event|09:02:00|         1|B   |Started|         1|         1
             1|       3|running_event|09:03:00|         1|C   |Running|         3|         1
             1|       4|started_event|09:04:00|         1|A   |Started|         1|         1
             1|       5|running_event|09:05:00|         1|B   |Running|         3|         1
             1|       6|running_event|09:06:00|         1|C   |Running|         3|         1
             1|       7|running_event|09:07:00|         1|A   |Running|         3|         1
             1|       8|stopped_event|09:08:00|         1|A   |Stopped|         2|         1
             1|       9|stopped_event|09:09:00|         1|B   |Stopped|         2|         1
             2|       1|started_event|09:13:00|         1|A   |Started|         1|         3
             2|       2|started_event|09:14:00|         1|B   |Started|         1|         3
             2|       3|running_event|09:15:00|         1|C   |Running|         3|         3
             2|       4|started_event|09:16:00|         1|A   |Started|         1|         3
             2|       5|running_event|09:17:00|         1|B   |Running|         3|         3
             2|       6|running_event|09:18:00|         1|C   |Running|         3|         3
             2|       7|running_event|09:19:00|         1|A   |Running|         3|         3

关于mysql - 通过比较前后记录创建自定义 session 标识符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48590572/

相关文章:

sql-server - 如何测试SQL Server数据库是否处于单用户模式

mysql - 如何让我的 Teradata 查询提示输入 ?YYYYMMDD AND ?YYYYMMDD 和 之间的日期

MySQL 5.7 Windows,表键问题?

mysql - 以编程方式使用 Node.js 读取 JSON 和 INSERT INTO mysql 的最佳方法

mysql - 如何在 Windows 中编译 MySQL 示例插件

sql-server - 为什么 count(1/null) 有效但 count(null/null) 无效?

sql-server - 无法将数据库导入/部署到 SQL Azure : "The service objective (Business/Web) specified is invalid."

java - 从 Spark 读取 Teradata 时出错。它加载了表并显示了架构,但无法给出数据集结果

sql - Teradata 中的 QUALIFY ROW_NUMBER

mysql - MySQL Polygon 数据类型是否比将多边形存储为 JSON 对象(文本)更好?