Home > database >  Populate an array with certain values at certain positions in snowflake
Populate an array with certain values at certain positions in snowflake

Time:04-12

Let's say that I have this table:

Key Index Value
1 3 10
1 5 18
1 14 4
2 2 11
2 13 24
2 29 40

I want to construct an array in Snowflake where the dimension of the array is always 50, the default value is zero, and I wanna populate the array with certain values at certain positions according to Index and Value columns. The desired output is

Key Array
1 [0,0,0,10,0,18,0,0,0,0,0,0,0,0,4,0,...,0]
2 [0,0,11,0,...,0,24,0,...,0,40,0,...,0]

CodePudding user response:

Maybe something like this.

with my_data as (
    -- data table as cte
    select
        1 as Key,
        3 as Index,
        10 as Value
    union all
    select
        1,
        5,
        18
    union all
    select
        1,
        14,
        4
    union all
    select
        2,
        2,
        11
    union all
    select
        2,
        13,
        24
    union all
    select
        2,
        29,
        40
),
index_cte as (
    -- generate 1-50 index values
    select
        row_number() over (
            order by
                seq4()
        ) as fixed_index
    from
        table(generator(rowcount => 50))
),
keys_fixed_index as(
    -- cross join distinct keys with fixed_index values
    select
        distinct key,
        fixed_index
    from
        my_data
        cross join index_cte
)
select
    distinct
    t1.key,
    ARRAY_AGG(ifnull(value, 0)) WITHIN GROUP (
        order by
            t1.fixed_index asc
    ) OVER (PARTITION BY t1.key) as array
from
    keys_fixed_index t1
    left join my_data t2 on t1.key = t2.key
    and t1.fixed_index = t2.index
order by
    key
KEY ARRAY
1 [ 0, 0, 10, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
2 [ 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]

CodePudding user response:

UPDATED TO USE A SET BASED APPRAOCH

Instead of using string manipulations and aggregations, this can be done in a much simpler way using a set based approach. I don't know why it didn't occur to me sooner.

with cte as

(select key,
        row_number() over (partition by key order by 1)-1 as index, 
        0 as value
 from table(generator(rowcount=>50)) cross join (select distinct key from t)

 union
 select key,index,value 
 from t

 minus
 select key,index,0
 from t)

select key,array_agg(value) within group (order by index) as value_array
from cte
group by key
  • Related