【问题标题】:SQL to get 3 adjacent actions without duplicate from the flagsSQL 从标志中获取 3 个相邻的操作而不重复
【发布时间】:2021-05-09 14:57:14
【问题描述】:

我有一个与question#66044663 有点相似但更复杂的问题。

这是我的虚拟数据。

我想从每个用户的标志中获取 3 个相邻的操作(不重复)。

这是描述我想法的图表。

这就是我想要的:

如何实现 SQL(我使用 Google Bigquery)? 我知道函数 LAG 可能是一个解决方案,但我不知道如何避免重复操作。

希望有人能照亮我。谢谢一百万!

这是生成数据集的代码。

WITH
src_table AS (
SELECT 'Jack' AS User, 1 AS Sequence, 'Eat' AS Action, '' AS Flag UNION ALL
SELECT 'Jack' AS User, 2 AS Sequence, 'Work' AS Action, '' AS Flag UNION ALL
SELECT 'Jack' AS User, 3 AS Sequence, 'Sleep' AS Action, 'Flag A' AS Flag UNION ALL
SELECT 'Jack' AS User, 4 AS Sequence, 'Exercise' AS Action, 'Flag B' AS Flag UNION ALL
SELECT 'Kenny' AS User, 1 AS Sequence, 'Run' AS Action, '' AS Flag UNION ALL
SELECT 'Kenny' AS User, 2 AS Sequence, 'Eat' AS Action, '' AS Flag UNION ALL
SELECT 'Kenny' AS User, 3 AS Sequence, 'Eat' AS Action, '' AS Flag UNION ALL
SELECT 'Kenny' AS User, 4 AS Sequence, 'Work' AS Action, 'Flag C' AS Flag UNION ALL
SELECT 'Kenny' AS User, 5 AS Sequence, 'Work' AS Action, 'Flag D' AS Flag UNION ALL
SELECT 'May' AS User, 1 AS Sequence, 'Work' AS Action, 'Flag A' AS Flag
)

【问题讨论】:

    标签: sql group-by google-bigquery sequence partition-by


    【解决方案1】:

    考虑下面

    select user, actions.action_sequence, flag  from (
      select *, (
        select as struct count(1) actions_count,
          string_agg(action, ' >> ' order by grp) action_sequence
        from (
          select action, grp from t.arr group by action, grp
        )) actions
      from (
        select *, array_agg(struct(action, grp)) 
          over(partition by user order by grp desc range between current row and 2 following) arr
        from (
          select *, countif(change) over(partition by user order by sequence) grp
          from (
            select *, action != lag(action) over(partition by user order by sequence) change
            from src_table
          )
        )
      ) t
    )
    where flag != '' 
    and actions.actions_count = 3
    # order by user, sequence
    

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

    注意:上述解决方案适用于任意数量的相邻操作(无重复) - 您只需在两个相应的位置更改它(2 和 3)

    over(partition by user order by grp desc range between current row and 2 following) arr    
    

    and actions.actions_count = 3   
    

    【讨论】:

    • 我喜欢这个答案,因为它很灵活,我可以通过您提供的代码直接得到正确答案。更重要的是,我可以从答案中学到很多东西。 RANGE 语句对我来说是一项高级技能,所以我花了很多时间来理解你的代码,这就是为什么我这么晚才评论你的回答。感谢您的回复!
    【解决方案2】:

    这与您之前的查询类似。如果我假设具有相同操作的相邻行最多有一个标志,那么我们可以使用 gaps-and-islands 方法。 . .然后滞后。

    第一步是:

    select user, min(sequence) as seqnuence, action, max(flag) as flag
    from (select t.*,
                 row_number() over (partition by user order by sequence) as seqnum
          from t
         ) t
    group by user, sequence - seqnum;
    

    然后,以此为“基础”数据,我们可以使用滞后:

    with cte as (
          select user, min(sequence) as seqnuence, action, max(flag) as flag
          from (select t.*,
                       row_number() over (partition by user order by sequence) as seqnum
                from t
               ) t
          group by user, sequence - seqnum
         )
    select user, prev_action, prev_action_2, action, flag
    from (select t.*,
                 lag(action) over (partition by user order by sequence) as prev_action,
                 lag(action, 2) over (partition by user order by sequence) as prev_action2
          from t
         ) t
    where prev_action is not null;
    

    如果具有相同活动的用户可以有不同的标志,如果您能提出 问题,我将不胜感激。在新问题中,如果您包含 SELECT 语句以生成正在使用的示例数据,将会很有帮助。

    【讨论】:

    • 我在使用第一部分时遇到了错误。错误信息是:Column flag 包含一个聚合函数,在 GROUP BY 中是不允许的。顺便说一句,我在我的问题中添加了 SELECT 语句供您参考:)
    • @LucasLee。 . . flag 不应该在 group by 中。
    【解决方案3】:

    您可以使用 RANK() 对重复项进行排序,然后对 RANK() = 1 进行过滤以获取每个重复项的第一个(或最后一个)。然后问题就归结为您所指的另一个问题。

    【讨论】:

    • 感谢您的回复。我想知道如何通过原始代码对标志 C 和 D 中的重复操作进行排名?
    • sequence 上过滤不大于与给定标志对应的那个吗?
    猜你喜欢
    • 2021-05-08
    • 2013-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 1970-01-01
    相关资源
    最近更新 更多