【问题标题】:Google BigQuery: Rolling Count DistinctGoogle BigQuery:滚动计数不同
【发布时间】:2016-05-12 11:50:33
【问题描述】:

我有一张表,其中只是日期和用户 ID 的列表(未汇总)。

我们通过计算过去 45 天内出现的不同 ID 数量,为给定日期定义了一个名为活跃用户的指标。

我正在尝试在 BigQuery 中运行一个查询,该查询每天返回当天加上当天的活跃用户数(统计从 45 天前到今天的不同用户)。

我尝试过窗口函数,但不知道如何根据列中的日期值定义范围。相反,我相信下面的查询可以在 MySQL 这样的数据库中运行,但在 BigQuery 中则不行。

SELECT 
  day,
  (SELECT 
    COUNT(DISTINCT visid) 
   FROM daily_users
   WHERE day BETWEEN DATE_ADD(t.day, -45, "DAY") AND t.day
   ) AS active_users
FROM daily_users AS t
GROUP BY 1

这在 BigQuery 中不起作用:“SELECT 子句中不允许子选择。”

如何在 BigQuery 中执行此操作?

【问题讨论】:

    标签: sql google-bigquery


    【解决方案1】:

    BigQuery documentation 声称 count(distinct) 用作窗口函数。但是,这对您没有帮助,因为您不是在寻找传统的窗框。

    一种方法是在访问后为每个日期添加一条记录:

    select theday, count(distinct visid)
    from (select date_add(u.day, n.n, "day") as theday, u.visid
          from daily_users u cross join
               (select 1 as n union all select 2 union all . . .
                select 45
               ) n
         ) u
    group by theday;
    

    注意:在 BigQuery 中生成一系列 45 个整数可能有更简单的方法。

    【讨论】:

      【解决方案2】:

      以下内容应该适用于 BigQuery

      #legacySQL
      SELECT day, active_users FROM (
        SELECT 
          day, 
          COUNT(DISTINCT id) 
            OVER (ORDER BY ts RANGE BETWEEN 45*24*3600 PRECEDING AND CURRENT ROW) AS active_users
        FROM (
          SELECT day, id, TIMESTAMP_TO_SEC(TIMESTAMP(day)) AS ts 
          FROM daily_users
        )
      ) GROUP BY 1, 2 ORDER BY 1  
      

      以上假设day 字段表示为“2016-01-10”格式。
      如果不是这种情况,您应该在最内部选择中调整TIMESTAMP_TO_SEC(TIMESTAMP(day))

      另外请查看 BigQuery 中的 COUNT(DISTINC) 详细信息

      BigQuery 标准 SQL 更新

      #standardSQL
      SELECT 
        day, 
        (SELECT COUNT(DISTINCT id) FROM UNNEST(active_users) id) AS active_users
      FROM (
        SELECT 
          day, 
          ARRAY_AGG(id) 
            OVER (ORDER BY ts RANGE BETWEEN 3888000 PRECEDING AND CURRENT ROW) AS active_users
        FROM (
          SELECT day, id,  UNIX_DATE(PARSE_DATE('%Y-%m-%d', day)) * 24 * 3600 AS ts 
          FROM daily_users
        )
      ) 
      GROUP BY 1, 2 
      ORDER BY 1  
      

      您可以使用下面的虚拟样本测试/玩它

      #standardSQL
      WITH daily_users AS (
        SELECT 1 AS id, '2016-01-10' AS day UNION ALL
        SELECT 2 AS id, '2016-01-10' AS day UNION ALL
        SELECT 1 AS id, '2016-01-11' AS day UNION ALL
        SELECT 3 AS id, '2016-01-11' AS day UNION ALL
        SELECT 1 AS id, '2016-01-12' AS day UNION ALL
        SELECT 1 AS id, '2016-01-12' AS day UNION ALL
        SELECT 1 AS id, '2016-01-12' AS day UNION ALL
        SELECT 1 AS id, '2016-01-13' AS day
      )
      SELECT 
        day, 
        (SELECT COUNT(DISTINCT id) FROM UNNEST(active_users) id) AS active_users
      FROM (
        SELECT 
          day, 
          ARRAY_AGG(id) 
            OVER (ORDER BY ts RANGE BETWEEN 86400 PRECEDING AND CURRENT ROW) AS active_users
        FROM (
          SELECT day, id,  UNIX_DATE(PARSE_DATE('%Y-%m-%d', day)) * 24 * 3600 AS ts 
          FROM daily_users
        )
      ) 
      GROUP BY 1, 2 
      ORDER BY 1  
      

      【讨论】:

      • 此查询在标准 sql 上失败:“如果指定了 DISTINCT,则不允许 Windows ORDER BY”。你有什么想法如何做这样的滑动窗口不同计数?
      • 在回答此问题时 - 尚无可用的标准 SQL。标准 SQL 的 Beta 版可用性仅在 2016 年 6 月才宣布。显然,此答案是为 BigQuery Legacy SQL 提供的,它仍然适用于 Legacy。我建议您发布您的问题以及您的具体细节 - 我或这里的任何其他人将很乐意回答您的问题!承诺!
      • @GeorgeHilios - 请参阅上述答案中标准 sql 的更新!
      • 我实际上做了同样的事情 :) 有趣的是,我们想出了相同的解决方法。在对大数据集进行操作时,该数组可能会变得非常大,因此我还必须添加一些嵌套查询,以便在聚合之前进一步修剪它。很乱。我希望 Google 能尽快简化这个过程!
      • @GeorgeHilios - 当然。如果它解决了您原始评论中的问题,请考虑投票:o)
      猜你喜欢
      • 2020-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-28
      • 2020-11-30
      • 1970-01-01
      • 2015-06-20
      • 2021-08-20
      相关资源
      最近更新 更多