【问题标题】:how to cumulatively combine arrays from previous rows into one aggregate array? (Snowflake/SQL)如何将前几行的数组累积组合成一个聚合数组? (雪花/SQL)
【发布时间】:2022-10-25 05:37:28
【问题描述】:

想象一下,我有一个包含两列的表,一个日期 DATE 和一个字符串 ITEMS 数组。

我想创建一个列 ITEMS_AGG ,其中包含前行中所有数组的聚合,即类似于:

DATE   ITEMS      ITEMS_AGG
1      a, b       a, b
2      a, c       a, b, c
3      b, c       a, b, c
4.     a, d       a, b, c, d
5.     a, b, e    a, b, c, d, e

等等

【问题讨论】:

    标签: sql snowflake-cloud-data-platform


    【解决方案1】:

    具有不同定义的累积array_aggJavaScript UDTF.

    样本数据:

    CREATE OR REPLACE TABLE test(grp TEXT, date INT, ITEMS ARRAY)
    AS
         SELECT  'X',1,  ARRAY_CONSTRUCT('a', 'b')       
    UNION SELECT 'X',2,  ARRAY_CONSTRUCT('a', 'c')       
    UNION SELECT 'X',3,  ARRAY_CONSTRUCT('b', 'c')       
    UNION SELECT 'X',4,  ARRAY_CONSTRUCT('a', 'd')       
    UNION SELECT 'X',5,  ARRAY_CONSTRUCT('a', 'b', 'e')
    UNION SELECT 'Y',1,  ARRAY_CONSTRUCT('z')
    UNION SELECT 'Y',2,  ARRAY_CONSTRUCT('y','x')
    UNION SELECT 'Y',3,  ARRAY_CONSTRUCT('y');
    

    功能:

    CREATE OR REPLACE FUNCTION aggregate (TS ARRAY)
    RETURNS table (output variant)
    LANGUAGE JAVASCRIPT
    STRICT
    IMMUTABLE
    AS '
    {
      initialize: function(argumentInfo, context) {
            this.result = [];
        },
      processRow: function (row, rowWriter, context) {
           this.result = [...new Set(this.result.concat(row.TS))];          
           rowWriter.writeRow({OUTPUT: this.result.sort()});           
       }
     }
     ';
    

    询问:

    SELECT *
    FROM test,  TABLE(aggregate(ITEMS) OVER(PARTITION BY grp ORDER BY date))
    ORDER BY grp, date;
    

    输出:

    【讨论】:

      【解决方案2】:

      好吧,这并不完全是您想要的,您可以使用递归 cte 进行加倍聚合,因为此 SQL 没有 ARRAY_CAT(DISTINCT) :

      WITH data AS (
          SELECT column1 as date, split(column2, ',') as items FROM VALUES
          (1, 'a,b'),
          (2, 'a,c'),
          (3, 'b, c'),
          (4, 'a,d'),
          (5, 'a,b,e')
      ), rec AS (
          WITH RECURSIVE r_cte AS (
              SELECT date as date, items
              FROM data
              WHERE date = 1
              
              UNION ALL
              
              SELECT r.date+1 as r_date, array_cat(r.items, d.items) as items
              FROM r_cte r
              JOIN data d 
                  ON r.date + 1 = d.date
          )
          SELECT * from r_cte
      )
      SELECT *
      FROM rec;
      
      DATE ITEMS
      1 [ "a", "b" ]
      2 [ "a", "b", "a", "c" ]
      3 [ "a", "b", "a", "c", "b", " c" ]
      4 [ "a", "b", "a", "c", "b", " c", "a", "d" ]
      5 [ "a", "b", "a", "c", "b", " c", "a", "d", "a", "b", "e" ]

      但实际上你应该使用 Lukasz 解决方案。

      【讨论】:

        【解决方案3】:

        派对迟到了,但如果您要过来,我们可以使用 lateral 和 array_union_agg 加入

        with cte (grp, dt, items) as
        
        (select 'x', 1, ['a', 'b'] union all   
         select 'x', 2, ['a', 'c'] union all        
         select 'x', 3, ['b', 'c'] union all        
         select 'x', 4, ['a', 'd'] union all        
         select 'x', 5, ['a', 'b', 'e'] union all 
         select 'y', 1, ['z'] union all 
         select 'y', 2, ['y','x'] union all 
         select 'y', 3, ['y'])
        
        
        select *
        from cte a, lateral(select array_union_agg(b.items) as items_agg 
                             from cte b 
                             where a.grp=b.grp and b.dt<=a.dt) t2
        order by a.grp, a.dt
        

        【讨论】:

          猜你喜欢
          • 2011-01-02
          • 2021-08-19
          • 1970-01-01
          • 2022-07-06
          • 2011-12-07
          • 2016-05-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多