按日查看活动表中所有用户的计数,而不会丢失具有0计数的用户

时间:2015-06-28 23:58:14

标签: sql oracle sas

所以我有一个表包含用户在一段时间内的日志活动,看起来像这样:

message_table

+--------+------------+----------------------+
| Userid | Message_Id |      Timestamp       |
+--------+------------+----------------------+
| 3433   | 10051      | 05-Jun-2015 04:00:00 |
| 6321   | 10052      | 05-Jun-2015 04:01:00 |
| 83821  | 10053      | 05-Jun-2015 04:01:15 |
| ...    | ...        | ...                  |
| 2041   | 20052      | 15-Jun-2015 23:59:00 |
+--------+------------+----------------------+

我还有一个用户列表,我对进行活动计数感兴趣。

interesting_userid

╔════════╗
║ Userid ║
╠════════╣
║ 3433   ║
║ 83821  ║
║ 1454   ║
╚════════╝

我的目标:我想选择一个特定的时间表(例如,在6月7日到6月9日之间)。我希望在时间范围内有一个表格,包括所有用户ID,然后是各自的计数。

这是我正在寻找的观点:

+-----------+--------+--------------+

| DayOfWeek | Userid | num_messages |
+-----------+--------+--------------+
| Jun 7     | 3433   | 2            |
| Jun 7     | 83821  | 5            |
| Jun 7     | 1454   | 0            |
| Jun 8     | 3433   | 1            |
| Jun 8     | 83821  | 5            |
| Jun 8     | 1454   | 2            |
| Jun 9     | 3433   | 0            |
| Jun 9     | 83821  | 3            |
| Jun 9     | 1454   | 1            |
+-----------+--------+--------------+

相反,我得到的是count()为0的行被排除在外:

+-----------+--------+--------------+
| DayOfWeek | Userid | num_messages |
+-----------+--------+--------------+
| Jun 7     | 3433   | 2            |
| Jun 7     | 83821  | 5            |
| Jun 8     | 3433   | 1            |
| Jun 8     | 83821  | 5            |
| Jun 8     | 1454   | 2            |
| Jun 9     | 83821  | 3            |
| Jun 9     | 1454   | 1            |
+-----------+--------+--------------+

查询看起来像这样:

select some_date_interval_function(me.timestamp) as DayOfWeek, iu.userid, count(me.message_id)
from interesting_userid iu
left join message_table me
    on iu.userid = me.userid
where me.timestamp between '07-Jun-2015' and '09-Jun-2015'
group by DayOfWeek, iu.userid

3 个答案:

答案 0 :(得分:1)

您可以在此处测试查询:SQL Fiddle

WITH valid_date_range(valid_date) AS (
   SELECT x.range_start + LEVEL - 1
     FROM (SELECT TO_DATE('2015-06-07', 'YYYY-MM-DD') AS range_start,
                  TO_DATE('2015-06-09', 'YYYY-MM-DD') AS range_end
             FROM dual) x
  CONNECT BY x.range_start + LEVEL - 1 <= x.range_end),
message_count_by_user_and_date(message_date, userid, num_messages) AS (
  SELECT d.valid_date, iu.userid, COUNT(me.message_id)
    FROM interesting_userid iu
    JOIN valid_date_range d ON 1 = 1
    LEFT JOIN message_table me
      ON me.userid = iu.userid
     AND me.timestamp >= d.valid_date
     AND me.timestamp < d.valid_date + 1
   GROUP BY d.valid_date, iu.userid)
SELECT some_date_interval_function(m.message_date) AS DayOfWeek,
       m.userid,
       m.num_messages
  FROM message_count_by_user_and_date m
 ORDER BY m.message_date, m.userid;

答案 1 :(得分:0)

你可以试试这个:

select u.userid, DayOfWeek, tot_messages
from selected_users u
left join ( select userid, 
   some_date_interval_function(me.timestamp) as DayOfWeek, 
   count(*) tot_messages 
   from messages where tstamp between '07-Jun-2015' and '09-Jun-2015'
   group by userid) e
on u.userid=e.userid;

将表和列更改为您的,并将所需的列添加到最终选择中。

答案 2 :(得分:0)

最简单的方法是将条件从where子句移到on子句:

select some_date_interval_function(me.timestamp) as DayOfWeek, iu.userid,
       count(me.message_id)
from interesting_userid iu left join
     message_table me
     on iu.userid = me.userid and
        me.timestamp between '07-Jun-2015' and '09-Jun-2015'
group by DayOfWeek, iu.userid;

您的from条款正在将left join变为inner join

我建议您使用ANSI标准格式编写日期:

from interesting_userid iu left join
     message_table me
     on iu.userid = me.userid and
        me.timestamp between date '2015-06-07' and '2015-06-07'