【问题标题】:How can I count users in a month that were not present in the month before?如何计算一个月内不存在于前一个月的用户?
【发布时间】:2017-04-14 22:35:17
【问题描述】:

我正在尝试按月计算上个月不存在的唯一用户。因此,如果用户有 1 月的记录,然后有 2 月的另一个记录,那么我只会计算该用户的 1 月。

user_id    time
a1         1/2/17
a1         2/10/17
a2         2/18/17
a4         2/5/17
a5         3/25/17

我的结果应该是这样的

Month   User Count
January     1
February    2
March       1

【问题讨论】:

  • “因此,如果用户有 1 月的记录,然后又有 2 月的记录,那么我只会计算该用户的 1 月。”你的意思是你只会数二月?
  • 他只想数第一次……

标签: sql google-bigquery psql


【解决方案1】:

我对 BigQuery 不是很熟悉,但这里是我使用 TSQL 解决问题的方法。我想您可以在 BigQuery 中使用类似的逻辑。

1)。首先按 user_id 排序数据,然后按时间排序。在 TSQL 中,您可以通过以下方式完成此操作并将其存储在公用表表达式中,您将在此之后的步骤中查询该表达式。

;WITH cte AS
(
select  ROW_NUMBER() OVER (PARTITION BY [user_id] ORDER BY [time]) AS rn,*
from    dbo.employees
)

2)。接下来只查询 rn = 1 的行(特定用户的第一次出现)并按月分组。

select    DATENAME(month, [time]) AS [Month], count(*) AS user_count 
from      cte
where     rn = 1    
group by  DATENAME(month, [time])

这是假设 2017 年是您要处理的唯一年份。如果您处理的时间超过一年,您可能希望第 2 步看起来像这样:

select    year([time]) as [year],  DATENAME(month, [time]) AS [month], 
          count(*) AS user_count 
from      cte
where     rn = 1    
group by  year([time]), DATENAME(month, [time])

【讨论】:

    【解决方案2】:

    首先按用户 ID 和月份聚合。然后使用lag()查看用户上个月是否在场:

    with du as (
          select date_trunc(time, month) as yyyymm, user_id
          from t
          group by date_trunc(time, month)
         )
    select yyyymm, count(*)
    from (select du.*,
                 lag(yyyymm) over (partition by user_id order by yyyymm) as prev_yyyymm
          from du
         ) du
    where prev_yyyymm is not null or
          prev_yyyymm < date_add(yyyymm, interval 1 month)
    group by yyyymm;
    

    注意:这使用了date 函数,但timestamp 也存在类似的函数。

    【讨论】:

      【解决方案3】:

      我理解问题的方式是-仅当同一用户在上个月出现时才将用户排除在给定月份。但是,如果同一用户在给定前几个月出现,但以前没有出现 - 用户应该被计算在内。

      如果这是正确的 - 请尝试以下 BigQuery 标准 SQL

      #standardSQL
      SELECT Year, Month, COUNT(DISTINCT user_id) AS User_Count
      FROM (
        SELECT *,
          DATE_DIFF(time, LAG(time) OVER(PARTITION BY user_id ORDER BY time), MONTH) AS flag
        FROM (
          SELECT 
            user_id,
            DATE_TRUNC(PARSE_DATE('%x', time), MONTH) AS time, 
            EXTRACT(YEAR FROM PARSE_DATE('%x', time)) AS Year, 
            FORMAT_DATE('%B', PARSE_DATE('%x', time)) AS Month
          FROM yourTable
          GROUP BY 1, 2, 3, 4
        )
      )
      WHERE IFNULL(flag, 0) <> 1
      GROUP BY Year, Month, time
      ORDER BY time 
      

      您可以使用下面的示例使用您问题中的虚拟数据来测试/玩上面的内容

      #standardSQL
      WITH yourTable AS (
        SELECT 'a1' AS user_id, '1/2/17' AS time UNION ALL
        SELECT 'a1', '2/10/17' UNION ALL
        SELECT 'a2', '2/18/17' UNION ALL
        SELECT 'a4', '2/5/17' UNION ALL
        SELECT 'a5', '3/25/17' 
      )
      SELECT Year, Month, COUNT(DISTINCT user_id) AS User_Count
      FROM (
        SELECT *,
          DATE_DIFF(time, LAG(time) OVER(PARTITION BY user_id ORDER BY time), MONTH) AS flag
        FROM (
          SELECT 
            user_id,
            DATE_TRUNC(PARSE_DATE('%x', time), MONTH) AS time, 
            EXTRACT(YEAR FROM PARSE_DATE('%x', time)) AS Year, 
            FORMAT_DATE('%B', PARSE_DATE('%x', time)) AS Month
          FROM yourTable
          GROUP BY 1, 2, 3, 4
        )
      )
      WHERE IFNULL(flag, 0) <> 1
      GROUP BY Year, Month, time
      ORDER BY time  
      

      输出是

      Year    Month       User_Count   
      2017    January     1    
      2017    February    2    
      2017    March       1    
      

      【讨论】:

      • 我认为这不是 OP 想要的。基本上是想统计一个月内第一次出现的用户,以后再也不统计了。
      • 在下面的声明中 were not present in the previous month 注意 month 的单数。不是months,而是month。无论如何 - 让我们把它留给 OP 来澄清! :o)
      • 同意让我们这样做。不知道为什么我提供我的 2 美分——我什至不富有;)
      【解决方案4】:

      试试这个查询:

      SELECT 
          t1.d,
          count(DISTINCT t1.user_id)
      FROM 
      (
          SELECT 
              EXTRACT(MONTH FROM time) AS d,
              --EXTRACT(MONTH FROM time)-1 AS d2,
              user_id
          FROM nbitra.tmp
      ) t1
      LEFT JOIN 
      (
          SELECT 
              EXTRACT(MONTH FROM time) AS d,
              user_id
          FROM nbitra.tmp
      ) t2
          ON t1.d = t2.d+1
      WHERE 
      (
          t1.user_id <> t2.user_id --User is in previous month
          OR t2.user_id IS NULL --To handle january, since there is no previous month to compare to
      )
      GROUP BY t1.d;
      

      【讨论】:

        猜你喜欢
        • 2022-10-14
        • 1970-01-01
        • 2021-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多