【问题标题】:Gaps and islands, whole division edition间隙和岛屿,全师版
【发布时间】:2022-01-02 18:19:42
【问题描述】:

所以我试图在一组数字上实现间隙和孤岛问题,这里有一个例子:

0 0 3 4 5 6 6 7 7 8 11 12 18 22

这是一个累积和,所以数字不能减少。我需要做的是按照这些规则将各个记录分成组:

  1. 组中的第一个(也是最小的)数字是“前导”数字
  2. 只有当一个数字的大小不超过某个数字(本例中假设为 7)时,它才能与其前导数字在同一组中
  3. 第一个超过 leading number + 7 的数字是下一组的前导数字

因此,对于上面显示的示例,组将是: 0 0 3 4 5 6 6 7 7 8 11 12 18 22

这几乎就像一个数字除以差距,然后得到一个组号,但由于一组中的最后一个数字与下一组中的领先数字之间的差距可以是任何正数,这会得到更多随着序列的增长,更不正确。我尝试了case when sum(...) over(...) > 7 then sum(...) else 0 end,但它会影响不在第一组中的每个数字,所以我不知道如何再处理这个问题。任何帮助,将不胜感激!如果这很重要,表在雪花中

【问题讨论】:

    标签: sql snowflake-cloud-data-platform gaps-and-islands


    【解决方案1】:

    Snowflake 支持MATCH_RECOGNIZE,它旨在查找一系列行中的模式:

    SELECT col2,  bin_num
    FROM T
    MATCH_RECOGNIZE (
      ORDER BY col2
      MEASURES  MATCH_NUMBER() AS bin_num
      ALL ROWS PER MATCH
      AFTER MATCH SKIP PAST LAST ROW
      PATTERN ( A+ )
      DEFINE A AS FIRST(col2) + 7 >=  A.col2
    )
    ORDER BY COL2;
    

    db<>fiddle demo

    输出:


    要使用的另一种方法是递归 cte。

    WITH RECURSIVE cte AS (
       SELECT *, ROW_NUMBER() OVER(ORDER BY col2) AS rn
       FROM  t
    ), rec AS (
      SELECT col2, rn, col2 AS first_val, 1 AS grp
      FROM cte
      WHERE rn = 1
      UNION ALL
      SELECT c.col2, c.rn, IFF(r.first_val + 7 >= c.col2, r.first_val, c.col2), 
             grp + IFF(r.first_val + 7 >= c.col2, 0, 1)
      FROM rec r
      JOIN cte c
        ON r.rn = c.rn-1
    )
    SELECT col2, grp
    FROM rec
    ORDER BY col2;
    

    db<>fiddle demo

    相关:https://stackoverflow.com/a/53994970/5070879https://stackoverflow.com/a/52936314/5070879

    【讨论】:

    • 所以我尝试了 MATCH_RECOGNIZE 选项,我现在看到的是除了第一组之外的所有内容,通过在 DEFINE A AS FIRST_VALUE(col2) + 7 中交换 ">=" >= A.col2 to "
    • 在自己尝试挖掘之后,似乎根据 MA​​TCH_RECOGNIZE() Snowflake 文档, DEFINE A AS FIRST(col2) + 7 >= A.col2 is invalid since FIRST(...)不能在 DEFINE 子句中使用。有没有办法绕过它?
    • 嗨@H8oddo。 FIRST_VALUE 不能使用,因为它改变了模式的含义(每个分区的第一个值,在这种情况下只有一个分区)。是的,Snowflake 似乎目前不支持 FIRST 子句:docs.snowflake.com/en/sql-reference/constructs/…。可以用LAST() 重写它并更改正则表达式。就目前而言,您仍然可以使用递归版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2020-05-24
    • 1970-01-01
    • 2019-07-29
    • 1970-01-01
    • 1970-01-01
    • 2017-04-23
    相关资源
    最近更新 更多