【问题标题】:How to combine Cross Join and String Agg in Bigquery with date time difference如何将 Bigquery 中的 Cross Join 和 String Agg 与日期时间差结合起来
【发布时间】:2020-12-20 01:17:41
【问题描述】:

我正在尝试从下表开始

| user_id | touch     | Date       | Purchase Amount
| 1       | Impression| 2020-09-12 |0
| 1       | Impression| 2020-10-12 |0
| 1       | Purchase  | 2020-10-13 |125$
| 1       | Email     | 2020-10-14 |0
| 1       | Impression| 2020-10-15 |0
| 1       | Purchase  | 2020-10-30 |122
| 2       | Impression| 2020-10-15 |0
| 2       | Impression| 2020-10-16 |0
| 2       | Email     | 2020-10-17 |0

| user_id | path                           | Number of days between First  Touch and Purchase | Purchase Amount
| 1       | Impression,Impression,Purchase | 2020-10-13(Purchase) - 2020-09-12 (Impression) |125$
| 1       |  Email,Impression, Purchase    | 2020-10-30(Purchase) - 2020-10-14(Email) | 122$
| 2       | Impression, Impression, Email  | 2020-12-31 (Fixed date) - 2020-10-15(Impression) | 0$

本质上,每次在逗号分隔的字符串中遇到“购买”时,我都会尝试为表中的每个唯一用户创建一个新行。

另外,计算每个唯一用户的首次接触和首次购买之间的差异。当创建新行时,我们对同一用户执行相同操作,如上例所示。

从我收集的少量数据来看,我需要混合使用交叉连接和字符串 agg,但我尝试在字符串 agg 中使用 case 语句,但无法获得所需的结果。

在 SQL (Bigquery) 中是否有更好的方法。

谢谢

【问题讨论】:

    标签: sql google-bigquery gaps-and-islands date-arithmetic


    【解决方案1】:

    以下是 BigQuery 标准 SQL

    #standardSQL
    select user_id, 
      string_agg(touch order by date) path,
      date_diff(max(date), min(date), day) days,
      sum(amount) amount
    from (
      select user_id, touch, date, amount,
        countif(touch = 'Purchase') over win grp
      from `project.dataset.table`
      window win as (partition by user_id order by date rows between unbounded preceding and 1 preceding)
    )
    group by user_id, grp    
    

    如果应用于您问题的样本数据 - 输出是

    另一个变化,如果触摸中没有购买,我们会从我们设置的固定窗口计算天数。如何将其添加到上面的查询中?

    select user_id, 
      string_agg(touch order by date) path,
      date_diff(if(countif(touch = 'Purchase') = 0, '2020-12-31', max(date)), min(date), day) days,
      sum(amount) amount
    from (
      select user_id, touch, date, amount,
        countif(touch = 'Purchase') over win grp
      from `project.dataset.table`
      window win as (partition by user_id order by date rows between unbounded preceding and 1 preceding)
    )
    group by user_id, grp    
    

    有输出

    【讨论】:

    • @Mikhail,对不起,我不得不再做一次更改,如果触摸中没有购买,我们会从我们设置的固定窗口计算天数。如何将其添加到上面的查询中?
    • 你应该停止改变你的问题——而是根据你已经得到的三个答案自己尝试一些事情!如果您仍然有问题 - 发布新问题,我们将为您提供帮助。同时,考虑投票并接受答案,否则,我没有理由继续回答:o)
    • 考虑投票赞成答案,同时我可以添加额外的条件(看起来我将有几分钟的时间):o)但正如我所说 - 你不应该改变你的问题尤其是在已经提供答案之后!
    【解决方案2】:

    表示如果有购买联系,您需要解决方案来划分行。

    使用以下查询:

    Select user_id,
           Aggregation function according to your requirement,
           Sum(purchase_amount)
      From
    (Select t.*,
           Sum(case when touch = 'Purchase' then 1 else 0 end) over (partition by user_id order by date) as sm
      From t) t
    Group by user_id, sm
    

    【讨论】:

    • 这会将每个“购买”放在每个组的开头而不是末尾。
    • @Popeye 我刚刚添加了一个我需要聚合的列。对更改感到抱歉
    • @GMB ,我已经明确提到根据要求使用聚合函数。
    【解决方案3】:

    我们可以将此视为一个差距和岛屿问题,每个岛屿都以购买结束。我们如何定义组?通过计算我们有多少购买提前(包括当前行) - 因此在查询中使用降序排序。

    select user_id, string_agg(touch order by date), 
        min(date) as first_date, max(date) as max_date,
        date_diff(max(date), min(date)) as cnt_days
    from (
        select t.*,
            countif(touch = 'Purchase') over(partition by user_id order by date desc) as grp
        from mytable t
    ) t
    group by user_id, grp
    

    【讨论】:

    • 我刚刚添加了一个需要聚合的列。对更改感到抱歉
    • @VardaanKhanted:只需将sum(amount) 添加到外部查询的select 子句中即可。
    【解决方案4】:

    您可以为每一行创建一个与table.touch = 'Purchase' 所在的实例数相对应的值,然后可以使用该值进行分组:

    with r as (select row_number() over(order by t1.user_id) rid, t1.* from table t1)
    select t3.user_id, group_concat(t3.touch), sum(t3.amount), date_diff(max(t3.date), min(t3.date))
    from (select 
           (select sum(r1.touch = 'Purchase' AND r1.rid < r2.rid) from r r1) c1, r2.* from r r2
        ) t3 
    group by t3.c1;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-16
      • 2015-05-19
      • 2017-04-06
      • 2018-05-07
      • 1970-01-01
      • 1970-01-01
      • 2012-03-05
      • 1970-01-01
      相关资源
      最近更新 更多