将转换列表(时间点)转换为状态列表(时间段)

时间:2012-06-08 18:20:29

标签: sql self-join

很久以前就做过类似的事了,但是当我觉得我现在做同样的事情时,它不起作用。

历史记录表是发生在帐户中的事件列表。其中一些事件是状态更改,在这种情况下,多用途详细信息列显示新状态。样品:

... where Event_Type = 'Change_Status';
Acct  Line  Event_Type     Detail
----  ----  -------------  -------
A        1  Change_Status  Created
A        4  Change_Status  Billed
A        7  Change_Status  Paid
A       10  Change_Status  Audited
B        1  Change_Status  Created
B        6  Change_Status  Billed

现在很容易将其加入到自身并得到一个时间表期间 WHERE A.Acct = B.Acct和A.Line< B.Line但我失败了两件事:

  1. 我还需要捕获最后一个状态,但在这种情况下没有结束(B. *)。我认为左连接会得到它(B.Line为空)但它没有。
  2. 需要消除跨越多个状态的时段,例如A-1到A-7尝试下面的两个项目,但任何一个都消除了所有内容。

    AND A.LINE = (SELECT Max(Line) FROM Events TEMP  
                  WHERE TEMP.Acct = A.Acct  
                    AND TEMP.Line < B.Line or B.Line is null);    
    AND NOT EXISTS (SELECT Line FROM Events TEMP   
                    WHERE TEMP.Acct = A.Acct  
                      AND TEMP.Line between A.Line and B.Line);  
    
  3. 如果其中任何一个不清楚,我需要创建的是

          Acct  Line     Acct  Line  Status
          ----  ----     ----  ----  -------
    from  A        1 To  A        4  Created
    from  A        4 To  A        7  Billed
    from  A        7 To  A       10  Paid
    from  A       10 To              Audited
    from  B        1 To  B        6  Created
    

1 个答案:

答案 0 :(得分:0)

我在postgres 9.1数据库上搜索了这个(所以,ymmv)。这是我提出的查询:

select
  x.acct, x.line, y.line, x.status
from
  statchanges x
    left join statchanges y on x.acct = y.acct
                           and y.line > x.line
where
  y.line is null or
  (y.line - x.line =
    (select min(y1.line - x1.line)
     from statchanges x1, statchanges y1
     where x1.acct = x.acct
       and x1.line = x.line
       and x1.acct = y1.acct
       and y1.line > x1.line));

重要区别:1-在join子句中,我正在加入b.line&gt; a.line,而不是a.line&lt; b.line。这似乎是因为(在postgres 9.1上,至少)null在非空值之后排序,除非另有说明。 2-我正在跳过一些箍,以确保我在子查询中得到正确的min:进行非常相似的连接(不必进行左连接,因为我们不关心null s),并确保acctline与外部查询匹配。

我不确定这是否完全符合您的要求,但希望能为您提供一些探索方向。