从同一个表中添加多个“时间变化”

时间:2011-07-21 19:32:02

标签: sql oracle timestamp-analysis

每当用户状态发生变化时,我的表都会带一个时间戳。每天从“a”开始并始终进行a-> b-> c-> d-> e-> ...

所以我试图找到'a'和'b'之间的总时间加上'c'和'd'加'e'和'f'之间的时间等等。

这可以在两种状态之间获得时间:

SELECT cast(us2.status_timestamp as date) - cast(us1.status_timestamp as date)
FROM user_status US1, user_status US2
WHERE US1.statID = 'a' and us2.statID = 'b'
AND US1.user_ID = US2.user_ID
AND US1.work_date = US2.work_date

有没有办法在不多次执行此select语句的情况下执行此操作,然后添加结果?我觉得有更快的方法。

注意:使用Toad for Oracle

3 个答案:

答案 0 :(得分:1)

您可以使用LEAD和LAG分析函数

SELECT cast(status_timestamp as date) - cast(prior_status_timestamp as date) diff,
       user_id,
       work_date,
       statID
  FROM (
    SELECT status_timestamp,
           lag(status_timestamp) over 
              (partition by user_id, 
                            work_date 
               order by status_timestamp) prior_status_timestamp,
           user_id,
           statID,
           work_date
      FROM user_status )
 WHERE statID in ('b','d','f')      

对于表中的每一行,这将获得相同user_id和work_date的前一行的状态时间戳(因此每天每个用户的'a'行将具有NULL的prior_status_timestamp)。然后它显示当前行和前一行之间的差异。然后你可以适当地聚合。

答案 1 :(得分:1)

如果我正确理解您的要求,以下查询将起作用:

SELECT SUM (CAST (us2.status_timestamp AS date) - CAST (us1.status_timestamp AS date))
FROM   user_status us1, user_status us2
WHERE  CHR (ASCII (us1.statid) + 1) = us2.statid
   AND MOD (ASCII (us1.statid), 2) <> 0
   AND us1.user_id = us2.user_id
   AND us1.work_date = us2.work_date;
对于具有偶数ASCII值的字符,

MOD (ASCII (us1.statid), 2)将返回0,对于所有其他值,

{{1}}将返回其他值。 'a'是97,所以我们总是希望从这个值不是0开始。我们可以使用非常相似的逻辑来获得序列中的下一个值:将字母转换为它的ASCII值,加1,然后转换回来。在连接中使用该值可以让我们找到每个开始时间的相应结束。最后,我们只是总结所有的差异。

答案 2 :(得分:0)

SELECT US1.user_ID, SUM(difference)
FROM (
SELECT US1.user_ID, cast(us2.status_timestamp as date) - cast(us1.status_timestamp as date) AS difference
FROM user_status US1, user_status US2
WHERE 
   ((US1.statID = 'a' and us2.statID = 'b') OR
    (US1.statID = 'C' AND us2.statID = 'D') OR
    (US1.statID = 'E' AND us2.statID = 'F'))
AND US1.user_ID = US2.user_ID
AND US1.work_date = US2.work_date
) GROUP BY US1.user_id