【问题标题】:Shortest Query Possible, Big query for recursive checks可能的最短查询,递归检查的大查询
【发布时间】:2019-11-15 08:47:59
【问题描述】:

假设我在大查询中有一个数据,一个月有数百万行。 例如:

|---------------------|------------------|
|      date           |     user         |
|---------------------|------------------|
|          01-12-2019 |   xyz            |
|---------------------|------------------|
|          02-12-2019 |   xyz            |
|---------------------|------------------|
|          03-12-2019 |   abc            |
|---------------------|------------------|

现在我想检索每日数据,接下来 14 天的重复用户计数,即 2019 年 1 月 12 日首次访问的用户,然后是未来 14 天内再次访问的重复用户计数(02-12-2019 - 15-12-2019)。我想出了检索相同的方法,但是对于某些特定日期,使用下面的查询。

 SELECT '2019-12-01' AS visit_date, COUNT(DISTINCT user) AS visitors_count
 FROM `user_data`
 WHERE
 date = '2019-12-01' AND user IN (SELECT user FROM `user_data`
 WHERE date between DATE_ADD('2019-12-01', INTERVAL 1 DAY) AND DATE_ADD('2019-12-01', INTERVAL 
 14 DAY) )
 GROUP BY 1

我可以使用的一种方法是 UNION ALL,这可能不是最好的解决方案,这就是为什么我愿意知道一些最佳实践,我必须养成这种情况的习惯。

【问题讨论】:

    标签: sql google-cloud-platform google-bigquery


    【解决方案1】:

    内联查询在这里应该非常有效:

    select 
        date,
        (
            select count(distinct u1.user) 
            from user_data u1 
            where u1.date 
                between date_add(u.date, interval 1 day) 
                and date_add(u.date, interval 14 day)
        ) visitors_count
    from (select distinct date from user_data) u
    

    为了提高性能,您需要在(date, user) 上建立索引。

    如果您有一个包含表中可用日期列表的参考表,则可以使用 if 而不是 select distinct: 这也可以加快查询速度。

    【讨论】:

    • 感谢您的回复,我收到此错误。 LEFT OUTER JOIN 不能在没有连接两边的字段相等的条件下使用。
    • @AmrishMishra: 但在此查询中没有 left outer join...您正在运行哪个查询会产生此错误?
    • 我只是复制了您的查询。
    • 到目前为止,我发现子查询无法访问别名'u'。
    • @GMB 。 . .有,只是你没看到。相关子查询实际上是一种外连接。不等式问题是 BQ 中的常见问题。如果有很多日期,这也不是任何数据库中最有效的方法。
    【解决方案2】:

    以下是 BigQuery 标准 SQL

    #standardSQL
    SELECT visit_day, COUNT(DISTINCT IF(visits_next_14_days, NULL, user)) AS repeating_visitors_count 
    FROM (
      SELECT visit_day, user, 0 = COUNT(1) OVER(
        PARTITION BY user 
        ORDER BY UNIX_DATE(visit_day) 
        RANGE BETWEEN 1 FOLLOWING AND 14 FOLLOWING
      ) visits_next_14_days
      FROM `project.dataset.user_data`
    )
    GROUP BY visit_day
    

    【讨论】:

    • 有什么资源建议可以提高我的 SQL 技能吗?
    • 我在某些时候是不是很粗鲁?对不起,如果我曾经在某个时候,我没有意识到是故意的。如果您有一些好的资源可以与我分享,将会有很多帮助。再次感谢您
    【解决方案3】:

    您可以通过使用union all 和聚合来解决此问题。关键是保持日期进出。所以:

    with ud as (
          select user, date, 1 as inc
          from user_data
          union all
          select user, date_add(date, interval 15 day), -1 as inc
          from user_data
         )
    select date,
           sum(inc) as change_on_day,
           sum(sum(inc)) over (order by date) as total_on_day
    from ud
    group by date
    order by date;
    

    编辑:

    您可以修改上述内容以获得客户的第一个积极公司和最后一个

    with ud as (
          select user, date, 1 as inc
          from (select ud.*,
                       lag(date) over (partition by user order by date) as prev_date
                from user_data ud
               ) ud
          where prev_date is null or prev_date < date_add(date, interval -14 day)
          union all
          select user, date_add(date, interval 15 day), -1 as inc
          from (select ud.*,
                       lead(date) over (partition by user order by date) as lead_date
                from user_data ud
               ) ud
          where next_date is null or next_date < date_add(date, interval 14 day)
         )
    select date,
           sum(inc) as change_on_day,
           sum(sum(inc)) over (order by date) as total_on_day
    from ud
    group by date
    order by date;
    

    【讨论】:

    • 错误的输出,可能它也包括那些在同一天重复的用户。最后,如果可能的话,请你解释一下背后的逻辑。谢谢。
    • @AmrishMishra 。 . . (1) 我确实解释了逻辑。 (2) 这回答了你提出的问题。如果您必须与在“活跃”期间回来的客户打交道,那么请提出一个新问题并非常明确地说明您需要的逻辑。
    • 如果他们的行为粗鲁,我很抱歉?我已经在我的问题中提到我需要在接下来的 14 天内重复的用户计数。请参阅我的问题中示例表下方的说明。很高兴对此进行讨论。
    • @AmrishMishra 。 . .不粗鲁,只是不完整。样本数据和问题未提及活动期间的“重叠”。
    • @AmrishMishra 。 . .您的问题在您的示例查询中确实有 count(distinct),因此我修改了答案以处理单个客户的重叠活动。
    猜你喜欢
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    • 2011-08-11
    • 2012-01-29
    • 2011-04-07
    相关资源
    最近更新 更多