每当用户状态发生变化时,我的表都会带一个时间戳。每天从“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
答案 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