团体参观活动

群组访问活动

我一直在研究查看群组活动的查询。

  • 独立访客数
  • 总访问次数
  • 移动端与桌面端访问
  • 群组成员访问比例
  • 每次访问平均阅读时间
  • 每次访问平均阅读帖子数
  • 每位成员平均阅读时间
  • 每位成员平均阅读帖子数

问题

  1. 我怀疑 user_visits 表每天每个 user_id 只记录一条数据,因为 visited_at 是 DATE 类型而不是 DATETIME 或 TIMESTAMP,即使用户在一天内从多种设备类型多次访问也是如此。当我按天运行查询时,我发现独立成员总数等于访问总数。有人能确认我的假设是否正确吗? 如果是,那么后续问题就变成了:如果用户一天内从笔记本电脑、台式机然后手机(顺序任意)访问三次,mobile 字段的值会发生什么变化?
  2. 奇怪的是,我还发现 AVG(uv.posts_read) 的值与 SUM(uv.posts_read)/COUNT(DISTINCT(uv.user_id)) 不相同,因此我很好奇我的查询是在哪里出错了,或者我是否对 user_visits 表或字段的理解有误。有人能谈谈这两种计算之间的区别吗?

查询:

摘要
-- [参数]
-- 空字符串 :group_name = 您的群组名称
-- 日期 :start_date = 2019/09/01
-- 日期 :end_date = 2019/10/01
-- 空字符串 :frame = day

with mobile as (
SELECT uv.id,
    count(DISTINCT(uv.user_id)) as UniqueMobile,
    date_part(:frame, uv.visited_at::date) as Day,
    g.name as GroupName
from user_visits uv
join users u on uv.user_id = u.id
join group_users gu on gu.user_id = u.id
join groups g on g.id = gu.group_id
where mobile = true
    and uv.visited_at >= :start_date::date
    and uv.visited_at < :end_date::date
    and g.name = :group_name
GROUP BY GroupName, Day, uv.id
    ), 
    
desktop as (
SELECT uv.id,
    count(DISTINCT(uv.user_id)) as UniqueDesktop,
    date_part(:frame, uv.visited_at::date) as Day,
    g.name as GroupName
from user_visits uv
join users u on uv.user_id = u.id
join group_users gu on gu.user_id = u.id
join groups g on g.id = gu.group_id
where mobile = false
    and uv.visited_at >= :start_date::date
    and uv.visited_at < :end_date::date
    and g.name = :group_name
GROUP BY GroupName, Day, uv.id
    )

   SELECT 
    date_part(:frame, uv.visited_at::date) as VisitDate,
    count(DISTINCT(uv.user_id)) as UniqueMembers, 
    count(uv.id) as AllVisits,
    count(m.UniqueMobile) as MobileVisits,
    count(d.UniqueDesktop) as DesktopVisits,
    round((count(DISTINCT(uv.user_id)) * 100.0) / groups.user_count, 2) as Percent,
    round(avg(uv.posts_read),2) as "Posts Read (avg Visit)",
    (interval '1' minute * ROUND((cast(AVG(uv.time_read) as decimal)/60), 2)) as "Read Time (avg Visit)",
    (SUM(uv.posts_read)/count(DISTINCT(uv.user_id))) as "Posts Read (avg Member)",
    date_trunc('second',(interval '1' minute * (ROUND((cast(SUM(uv.time_read) as decimal)/60), 2)/(count(DISTINCT(uv.user_id)))))) as "Read Time (avg Member)"

FROM users
join group_users on group_users.user_id = users.id
join groups on group_users.group_id = groups.id
LEFT join user_visits uv on uv.user_id = users.id
LEFT JOIN mobile m ON m.id = uv.id
LEFT JOIN desktop d ON d.id = uv.id
    where groups.name = :group_name
    AND uv.visited_at::date >= :start_date
    and uv.visited_at::date < :end_date
    
group by VisitDate, groups.user_count 

order by VisitDate asc

是的,这是正确的。

如果用户在新设备上访问时阅读了帖子,mobile 列将根据他们最后访问的设备进行更新。例如:如果用户一天开始时在桌面浏览器上阅读了 2 篇帖子,系统会为该用户 ID 创建一条 user_visits 记录,其中 posts_read 设为 2,mobile 设为 false。如果用户随后在移动设备上登录并阅读了另外 3 篇帖子,当天的 user_visits 记录将更新为 posts_read: 5mobile: true。您可以使用数据浏览器(Data Explorer)测试这一点,只需确保用户阅读的是他们之前未读过的帖子即可。

谢谢,关于最后一个问题有什么想法吗?我倾向于相信好的数据胜过坏的数据,而数据相似却又不完全相同这一点令人费解,尤其是考虑到您解释过在 user_visits 表中,每个 uv.user_id 在每个 uv.visited_at 只对应一个 uv.id

这可能不是特别有帮助,但这是我数据的一个示例:

访问日期 帖子阅读数(平均每次访问) 阅读数(平均每位成员)
13 1.18 1
14 4.15 4
15 7.18 7
16 6.15 6

当使用整数进行除法时,PostgreSQL 将返回整数。尝试使用 SUM(posts_read)::float / COUNT(DISTINCT(user_id)),看看是否仍然存在差异。您可能需要将结果四舍五入到两位小数。