小编典典

使用内部联接确定表中特定记录和相关事件之间的间隔

sql

我有一个简单的表,用于记录针对特定访问的事件:

Describe Histories;
    +------------------+
    | Field            |
    +------------------+
    | HistoryId        |
    | VisitId          |
    | Location         |
    | Event            |
    | EventTime        |
    +------------------+

个人与访问次数(VisitId)相关联。对于每次访问,一个人可能有多个历史记录。活动可以是入场,转场或出场。

我试图编写一个查询来计算每个位置在每个位置的持续时间。请注意,他们每次访问可能会多次访问一个位置。个人通过录取或转移事件进入场所,然后通过放电或转移离开场所。

如果某人进入位置“ A”,其录取或转移记录将列出位置“ A”,但是如果他们转移出去,其转移(或释放)将列出另一个位置,例如“ B”。

因此,我必须找到转移到位置“ A”和随后(及时)转移到位置“ B”之间的间隔。不评估位置内转移。

我知道该解决方案可能基于INNER JOIN,但是我不知该如何选择与最近的转帐“ in”相对应的转帐“ out”记录。

我认为这是相当复杂的-希望我的解释足够清楚。

任何指导,不胜感激。


阅读 134

收藏
2021-04-14

共1个答案

小编典典

假设转移或释放是一个独特的事件,您可以这样写

SELECT
   b.EventTime - a.EventTime        
FROM
   Histories a
   INNER JOIN Histories b
   ON a.VisitID = b.VisitID
WHERE
   a.event = 'Admission'
   and
   b.event in ('Transfer', 'Discharge')

如果您对上次汇款或清算感兴趣,您可以写

SELECT
   b.EventTime - a.EventTime        
FROM
   Histories a
   INNER JOIN  Histories b
    ON a.VisitID = b.VisitID

   INNER JOIN 
   (SELECT
         VisitId, 
         MAX(HistoryID) HistoryID
    FROM Histories 
    WHERE 
       b.event in ('Transfer', 'Discharge')
    GROUP BY 
       VisitId) maxHistory
   ON b.HistoryID = maxHistoryId.HistoryId

WHERE
   a.event = 'Admission'

但是,如Andriy M提到的那样,如果一次拜访可能导致多次拜访,则说明您存在“缺口与孤岛”问题(特别是孤岛)

在这种情况下,您需要以下内容

SELECT  
       a.VisitId,
       a.Event a_Event, 
       a.Event b_Event, 
       a.EventTime a_EventTime,
       b.EventTime b_EventTime,
       b_EventTime - a_EventTime

FROM   histories a 
       INNER JOIN histories B 
         ON a.visitID = b.visitID 
            AND a.EventTime < b.eventTime 
       INNER JOIN (SELECT a.VisitId, 
                          a.EventTime      a_EventTime, 
                          Min(b.EventTime) b_EventTime 
                   FROM   histories a 
                          INNER JOIN histories B 
                            ON a.visitID = b.visitID 
                               AND a.EventTime < b.eventTime 
                   GROUP  BY a_EventTime, 
                             a.VisitId) MinTime 
         ON a.VisitID = MinTime.VisitID 
            AND a.EventTime = a_EventTime 
            AND b.EventTime = b_EventTime

演示

使用以下样本数据

CREATE TABLE Histories 
    (
     HistoryId int auto_increment primary key, 
     VisitId int,
     Location varchar(20),
     Event varchar(20), 
     EventTime datetime
    );

INSERT INTO Histories
(VisitId, Location, Event, EventTime)
VALUES
(1, 'A', 'Admission', '2012-01-01'),
(1, 'A', 'Discharge', '2012-01-03'),
(2, 'B', 'Admission', '2012-01-02'),
(2, 'C', 'Transfer', '2012-01-05'),
(2, 'C', 'Discharge', '2012-01-06'),
(3, 'D', 'Admission', '2012-01-06'),
(3, 'E', 'Transfer', '2012-01-07'),
(3, 'F', 'Transfer', '2012-01-08'),
(3, 'F', 'Discharge', '2012-01-10');

您得到以下结果

VISITID    A_EVENT   B_EVENT    A_EVENTTIME                     B_EVENTTIME                     B_EVENTTIME - A_EVENTTIME
1          Admission Discharge  January, 01 2012 00:00:00-0800  January, 03 2012 00:00:00-0800  2000000
2          Admission Transfer   January, 02 2012 00:00:00-0800  January, 05 2012 00:00:00-0800  3000000
2          Transfer  Discharge  January, 05 2012 00:00:00-0800  January, 06 2012 00:00:00-0800  1000000
3          Admission Transfer   January, 06 2012 00:00:00-0800  January, 07 2012 00:00:00-0800  1000000
3          Transfer  Transfer   January, 07 2012 00:00:00-0800  January, 08 2012 00:00:00-0800  1000000
3          Transfer  Discharge  January, 08 2012 00:00:00-0800  January, 10 2012 00:00:00-0800  2000000

笔记:

  • 假设您不关心尚未进行相应排放/转移的录取/转移。
  • 如果您知道输入记录后eventTime不会更改,则可以使用historyID而不是eventime来确定事件的顺序。
  • 您知道如何以自己喜欢的格式获取事件时间差
2021-04-14