3

我们有一个包含以下列的表格:

SESSION_ID      USER_ID          CONNECT_TS
--------------  ---------------  ---------------
1               99               2013-01-01 2:23:33
2               101              2013-01-01 2:23:55
3               104              2013-01-01 2:24:41
4               101              2013-01-01 2:24:43
5               233              2013-01-01 2:25:01

我们需要获取每天的用户数量“活跃用户”的数量,这些用户被定义为在过去 45 天内使用过该应用程序的用户。这是我们想出的,但我觉得必须有更好的方法:

select trunc(a.connect_ts)
, count(distinct a.user_id) daily_users
, count(distinct b.user_id) active_users
from sessions a
  join sessions b
    on (b.connect_ts between trunc(a.connect_ts) - 45 and trunc(a.connect_ts))
where a.connect_ts between '01-jan-13' and '12-jun-13'
  and b.connect_ts between '01-nov-12' and '12-jun-13'
group by trunc(a.connect_ts);

我们查看了窗口函数,但看起来不支持不同的计数。我们还考虑过首先将聚合加载到临时表中,但不同的计数再次排除了它。有没有更好的方法来做到这一点?

4

2 回答 2

0

The first thing to do is generate a list of the days you're interesting in:

select (trunc(sysdate, 'yyyy') -1) + level as ts_day
from dual
connect by level <= to_number( to_char(sysdate, 'DDD' ) )

This will generate a table of dates from 01-JAN this year to today. Join your table to this sub-query. Using a cross join might not be particularly efficient, depending on how much data you have in the range. So please regard this as a proof of concept and tune as you need.

with days as
 ( select (trunc(sysdate, 'yyyy') -1) + level as ts_day
   from dual
   connect by level <= to_number( to_char(sysdate, 'DDD' ) ) )
select days.ts_day
       , sum ( case when trunc(connect_ts) = ts_day then 1 else 0 end ) as daily_users
       , sum ( case when trunc(connect_ts) between ts_day - 45 and ts_day then 1 else 0 end ) as active_users
from days
     cross join sessions  
where connect_ts between trunc(sysdate, 'yyyy') - 45 and sysdate
group by ts_day
order by ts_day
/
于 2013-06-14T03:18:51.607 回答
0

如果您的 Oracle 版本支持 WITH 语句,这可能会对您有所帮助:

with sel as (
select trunc(a.connect_ts) as logon_day
, count(distinct user_id) as logon_count
from sessions
group by trunc(connect_ts)
)
select s1.logon_day
, s1.logon_count as daily_users
, (select sum(logon_count) from sel where logon_day between s1.logon_day - 45 and s1.logon_day) as active_users
from sel s1

否则你必须这样写(执行速度要慢得多......):

select sel.logon_day
, sel.logon_count as daily_users
, (select count(distinct user_id) as logon_count
      from t_ad_session
      where trunc(connect_ts) between sel.logon_day - 45 and sel.logon_day) as active_users
from (select trunc(connect_ts) as logon_day, count(distinct user_id) as logon_count
      from t_ad_session
      group by trunc(connect_ts)) sel
于 2018-01-09T12:54:23.970 回答