使用子查询和分组依据每天计算每个国家/地区的 DAU 平均值

Posted

技术标签:

【中文标题】使用子查询和分组依据每天计算每个国家/地区的 DAU 平均值【英文标题】:Calculating DAU average for each country daily using subqueries and group by's 【发布时间】:2018-06-13 03:16:20 【问题描述】:

我正在尝试计算每个国家/地区在 1 个月内的 DAU 平均值。查询的工作是:

    识别唯一用户 查找上次登录的所有用户 月 将它们分成不同的日子 将它们细分为 各国 计算每个国家/地区的平均值。

到目前为止,我已经完成了第 1、2、3 和 4 步,但最后一步被证明很棘手。

该查询应该首先计算子查询,在该子查询中计算有多少活跃用户在上个月打开了应用程序,然后将它们分组到日期和国家/地区。 在此之后,它应该使用它在子查询中计算的所有 30 天数据来计算每个国家的平均 DAU。 结果将是一个国家列表及其平均 DAU。

到目前为止的查询如下所示:

SELECT Country, AVG(User_ID)
FROM usersession
WHERE User_ID IN
    (SELECT count(distinct us.User_ID)
     FROM usersession us
     WHERE Opened > current_timestamp - interval 1 month
     GROUP BY DAY(Opened), Country)
GROUP BY Country ORDER BY Country;

子查询执行第 1、2、3、4 步,但子查询之外的辅助查询并没有按预期工作。

表格如下(只是相关信息的一个简短示例):

ID    |  UserID  | Opened              | Country
-----------------------------------------------
233231          1   2017-11-20 08:00:00      NA
223214          2   2017-11-20 08:53:00      DK

预期结果(总共约 230 个国家/地区):

Country |  Average  
------------------
     NA    150354
     DK     60345
     FI     50242

实际结果:

+---------+--------------+
| Country | AVG(User_ID) |
+---------+--------------+
| NULL    |  804397.7297 |
|         |  746046.7500 |
| BR      |  893252.0000 |
| GB      |  935599.0000 |
| RU      |  993311.0000 |
| US      |  735568.0000 |
+---------+--------------+

【问题讨论】:

请修复你的数据库标签,看起来像 SQL-SERVER 而不是 mysql distinct 不是函数!删除那些多余的括号以使事情更清楚,即改为使用count(distinct us.User_ID) 其实是mysql :) 为了看得更清楚,我删除了箭头。 不清楚您问题中的查询是如何工作的。 User_ID IN (count of something GROUP BY something) 有什么意义?请edit澄清您的问题。 “不只是按预期工作” 不是问题描述。你想要什么?你得到了什么?发布预期与实际输出数据。 【参考方案1】:

我想这就是你想要的:

select
    country,
    sum(number_of_users) / count(distinct day_of_month) as daily_average_users
from
    (
        select 
           country,
           day(opened)             as day_of_month,
           count(distinct user_id) as number_of_users
        from
           user_session
        where
           opened > current_timestamp - interval 1 month
        group by
           country,
           day_of_month
    ) x
group by 
    country
order by 
    country;

我在 MySQL 5.7 上对此进行了测试:

create table user_session
(
    id       int,
    user_id  int,
    opened   timestamp,
    country  varchar(2)
);

insert into user_session (id, user_id, opened, country) values ( 1, 100, '2017-12-20 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values ( 2, 100, '2017-12-20 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values ( 3, 100, '2017-12-20 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values ( 4, 100, '2017-12-21 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values ( 5, 100, '2017-12-22 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values ( 6, 200, '2017-12-20 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values ( 7, 300, '2017-12-21 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values ( 8, 400, '2017-12-20 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values ( 9, 500, '2017-12-20 08:00:00', 'NA');
insert into user_session (id, user_id, opened, country) values (10, 600, '2017-12-20 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (11, 600, '2017-12-21 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (12, 700, '2017-12-20 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (13, 800, '2017-12-20 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (14, 800, '2017-12-21 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (15, 800, '2017-12-21 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (16, 900, '2017-12-20 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (17, 900, '2017-12-20 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (18, 900, '2017-12-22 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (19, 900, '2017-12-22 08:00:00', 'DK');
insert into user_session (id, user_id, opened, country) values (19, 1000, '2017-12-22 08:00:00', 'DK');

结果:

+---------+---------------------+
| country | daily_average_users |
+---------+---------------------+
| DK      |              2.6667 |
| NA      |              2.3333 |
+---------+---------------------+
2 rows in set (0.00 sec)

要获得正确的每日平均值,您需要在数据中表示该月的每一天(否则平均值超过了表示的天数)。如果不是这种情况,那么我们需要计算所考虑期间的天数。

【讨论】:

谢谢,它回答了我的问题:)

以上是关于使用子查询和分组依据每天计算每个国家/地区的 DAU 平均值的主要内容,如果未能解决你的问题,请参考以下文章

编写一个 SQL 查询来判断过去 6 个月中按国家/地区分组的最大销售额是一年中的哪一周?

在下拉菜单中分组地图国家

查询滚动日期范围和国家/地区中不同值的计数

哪个最快?计数子查询或分组依据

实体框架 LINQ - 具有分组依据的子查询

数据库:如果任何行中的字段 X 具有值 Y,则排除“分组依据”组