如何在Oracle表中找到下一个相关(但略有不同)的事务,可能使用LEAD?

时间:2013-07-17 14:14:58

标签: sql oracle analytics

我有一个包含大量事件的事务表,其中包含许多事件类型。我想对两个相关的事件类型做一些分析:transit-send和transit-receive。该表的示例如下所示:

 ItemID | EventType | TransactionDate
--------|-----------|-----------------
 11111  | send      | 2013-07-02
 22222  | receive   | 2013-07-02
 33333  | receive   | 2013-07-03
 22222  | send      | 2013-07-03
 11111  | receive   | 2013-07-04
 55555  | send      | 2013-07-05
 22222  | receive   | 2013-07-06
 44444  | send      | 2013-07-07
 22222  | send      | 2013-07-07
 44444  | receive   | 2013-07-08
 55555  | receive   | 2013-07-09
 22222  | receive   | 2013-07-10
 33333  | send      | 2013-07-11  

我需要做的是找到每个发送 - 接收配对,其中接收是发送后的第一个:11111在7/2发送并在7/4接收。 22222在7/3发送,然后在7/6收到。但是,在7/2和7/10也收到了22222。

我最初尝试使用连接来获得一些快速结果:

SELECT a.ItemID, a.EventType, a.TransactionDate, b.EventType, b.TransactionDate, b.TransactionDate - a.TransactionDate AS "Days"
FROM Transactions a, Transactions b
WHERE a.ItemID = b.ItemID
AND a.EventType = 'send'
AND b.EventType = 'receive'
AND a.TransactionDate < b.TransactionDate

我知道这不会得到我想要的实际结果,但这是一个快速而肮脏的近似。问题是,对于之后的每个接收,它将为同一发送返回多行(请注意第一个22222发送事务的重复):

 a.ItemID | a.EventType | a.TransactionDate | b.EventType | b.TransactionDate | Days
----------|-------------|-------------------|-------------|-------------------|------
 11111    | send        | 2013-07-02        | receive     | 2013-07-04        | 2
 22222    | send        | 2013-07-03        | receive     | 2013-07-06        | 3
 22222    | send        | 2013-07-03        | receive     | 2013-07-10        | 7
 22222    | send        | 2013-07-07        | receive     | 2013-07-10        | 3
 44444    | send        | 2013-07-07        | receive     | 2013-07-08        | 1
 55555    | send        | 2013-07-05        | receive     | 2013-07-09        | 4

Google建议我可以使用LEAD分析功能。这看起来很有希望,但鉴于我对它不熟悉,我不确定如何(或者如果)我可以使它适合我的模型,其中链接线没有直接配对(找到11111的下一个交易,无论类型)。我挂断了试图限制第一个交易发送,第二个交易接收。我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:2)

也许这会有所帮助:

select t.*,
       lead(EventType) over (partition by ItemId order by TransactionDate) as NextEventType,
       lead(TransactionDate) over (partition by ItemId order by TransactionDate) as NextEventType,
from Transactions t

然后您可以计算天数,但需要使用子查询:

select t.*,
       (case when NextEventType = 'receive' then NextEventDate - EventDate end) as days
from (select t.*,
             lead(EventType) over (partition by ItemId order by TransactionDate) as NextEventType,
             lead(TransactionDate) over (partition by ItemId order by TransactionDate) as NextEventDate
      from Transactions t
     ) t
where t.EventType = 'send'

有两个挑战。如果连续两个发送同一个项目但没有接收,则会发生一种情况。这将检测到这种情况并将接收分配给第二次发送。

另一个是时机。如果您在同一天有一个事件的发送和接收,则没有足够的信息可以知道哪个事先发生。这可能会造成问题。您的数据没有任何此类示例。如果出现这种情况,解决方案是包括时间戳。