按特定顺序发生的事件的SQL查询

7

我有以下的表格:

+--------+-------+------+--+
| Object | Event | Time |  |
+--------+-------+------+--+
| Obj1   | A     |    1 |  |
| Obj1   | B     |    3 |  |
| Obj2   | A     |    7 |  |
| Obj2   | B     |    4 |  |
+--------+-------+------+--+

我的目标是获取所有满足事件A和B的对象,并且A事件先发生(在时间上)。到目前为止,我只能查询出所有具有A和B事件的对象,但没有包括时间条件:

SELECT DISTINCT Object 
FROM
    (SELECT * 
     FROM
         (SELECT * 
          FROM table
          INNER JOIN 
              (SELECT Object Obj 
               FROM table 
               WHERE event LIKE '%A%' AS temp_table) ON table.Object = temp_table.Obj) AS temp_final 
     WHERE event LIKE '%B%') AS temp2;

因此,最终结果将是我得到一个仅包含以下内容的表格:
Obj1

由于这是唯一符合所有条件的对象。

时间列在现实生活中是一个日期戳记,但为了简单起见,我使用了整数。

感谢您的帮助。


我正在使用Vertica。我知道有LAG和LEAD等函数,但我想看看是否有一个通用的方法。另外,我仍然不完全明白如何在我的情况下使用LAG和LEAD :) - valenzio
5个回答

2
如果您只需要跟踪两个事件,这些事件发生在彼此之后,那么您可以使用单个JOIN来解决这个问题。无论Obj1有多少事件,都可以使用这种方法,因为您只对AB的存在及其相对顺序感兴趣。
select distinct t1.object
from TABLE t1
    inner join TABLE t2 on t1.object = t2.object
        and t2.time > t1.time
        and t1.event = 'A'
        and t2.event = 'B'

这里是代码运行结果的示例:
declare @tbl table (obj varchar(10), event varchar(1), time int)

insert @tbl values ('Obj1', 'A', 1), ('Obj1', 'B', 3), ('Obj2', 'A', 7), ('Obj2', 'B', 4)

select distinct t1.obj
from @tbl t1
    inner join @tbl t2 on t1.obj = t2.obj
        and t2.time > t1.time
        and t1.event = 'A'
        and t2.event = 'B'

1
我还在努力理解这里发生了什么,但似乎这样做是有效的。非常感谢。 - valenzio

1
这是一个紧凑的解决方案,适用于大多数关系型数据库。该解决方案不假定只有两个事件,并且适用于任意数量的事件。
SELECT t1.Object
FROM yourTable t1
INNER JOIN
(
    SELECT Object, MIN(Time) AS Time
    FROM yourTable
    GROUP BY Object
) t2
    ON t1.Object = t2.Object AND
       ((t1.Event = 'A' AND t1.Time = t2.Time) OR
        t1.Event <> 'A')
GROUP BY t1.Object
HAVING COUNT(*) = 2    -- change this count to match # of events

MySQL演示:

SQLFiddle


你在哪里定义对象必须具有事件B? - valenzio
我不明白,如果我有多个事件(例如A、B、C),并且我只想要那些按顺序只有事件A和B的对象,这该怎么做? - valenzio
它可能并不覆盖所有情况。但是例如,如果你想要首先获取 A,同时确保 BC 都存在,你只需要将计数更改为 3,我的查询将能够工作。无论如何,它绝对可以解决你的问题。 - Tim Biegeleisen
@valenzio Fiddle很容易崩溃。直接在Vertica中尝试查询即可。 - Tim Biegeleisen
你不需要提到 B,因为非 A 就意味着 B - Tim Biegeleisen
显示剩余5条评论

0

试试这个:

SELECT DISTINCT object
FROM yourtable t
WHERE EXISTS
    (SELECT FROM yourtable t3
    WHERE t3.object = t.object
    AND t3.event = 'A'
    AND EXISTS
        (SELECT 'B'
        FROM yourtbale t4
        WHERE t4.object = t3.object
        AND t4.event = 'B'
        AND t4.time > t3.time)
   )

0

如果您正在使用SQL Server:

SELECT
      A.[Object]
    , A.[Time]
    , B.[Time]
FROM
    (SELECT 
        Distinct [Object]
    FROM
        [table] AS A
    WHERE
        A.[Event] = 'A'
    ) AS A
        CROSS APPLY
    (SELECT
        TOP 1 *
    FROM
        [table] AS B
    WHERE
        [Event] = 'B'
        AND
        B.[Object] = A.[Object]
        AND
        A.[Time] < B.[Time]) AS B

0

针对 SQL Server:

;with A as
(select Object, MIN(Time) as Time from table where Event='A' group by Object)
, B as
(select Object, MIN(Time) aS Time from table where Event='B' group by Object)
Select A.Object from A inner join B on B.Object=A.Object where A.Time < B.Time

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接