簡體   English   中英

填充雪花中缺失的數據

[英]Filling in missing data in Snowflake

我在雪花中有一張這樣的桌子:

TIME   USER   ITEM
1      frank  1
2      frank  0
3      frank  0
4      frank  0
5      frank  2
6      alf    5
7      alf    0
8      alf    6
9      alf    0
10     alf    9

我希望能夠用下一個非零值替換所有零,所以最后我有一個這樣的表:

TIME   USER   ITEM
1      frank  1
2      frank  2
3      frank  2
4      frank  2
5      frank  2
6      alf    5
7      alf    6
8      alf    6
9      alf    9
10     alf    9

我將如何編寫在 Snowflake 中執行此操作的查詢?

您可以為此使用conditional_change_event函數 - 此處記錄

with base_table as (
    select
        t1.*,
        conditional_change_event(item) over (order by time desc) event_num
    from test_table t1
    order by time desc
)
select
    t1.time,
    t1.user,
    t1.item                    old_item,
    coalesce(t2.item, t1.item) new_item
from base_table t1
   left join base_table t2 on t1.event_num = t2.event_num + 1 and t1.item = 0
order by t1.time asc

以上 SQL 結果:

+----+-----+--------+--------+
|TIME|USER |OLD_ITEM|NEW_ITEM|
+----+-----+--------+--------+
|1   |frank|1       |1       |
|2   |frank|0       |2       |
|3   |frank|0       |2       |
|4   |frank|0       |2       |
|5   |alf  |2       |2       |
|6   |alf  |5       |5       |
|7   |alf  |0       |6       |
|8   |alf  |6       |6       |
|9   |alf  |0       |9       |
|10  |alf  |9       |9       |
+----+-----+--------+--------+

您可以使用lead(ignore nulls)

select t.*,
       (case when item = 0
             then lead(nullif(item, 0) ignore nulls) over (partition by user order by time)
             else item
        end) as imputed_item
from t;

你也可以使用first_value()first_value()

select t.*,
       last_value(nullif(item, 0) ignore nulls) over (partition by user order by time desc)
from t;

如果您想在 Snowflake 中使用 first_value() 或 last_value(),請記住,Snowflake 支持的窗口框架與此處記錄的 ANSI 標准不同。 這意味着,如果您想使用默認窗口框架 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,您必須在語句中明確包含它,否則,默認值為 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,這就是為什么 LAST_VALUE 示例來自以前的答案無法正常工作。 這是一個可行的示例:

select t.*,
       last_value(nullif(item, 0) ignore nulls) over (partition by user order by time desc rows between unbounded preceding and current row)
from t;

上述解決方案沒有錯......但這里有一種不同的方法......我認為它更簡單。

select * from good
union all
select 
     bad.time
    ,bad.user
    ,min(good.item) 
from  bad 
left outer join  
good on good.user=bad.user and good.time>bad.time 
group by
    1,2

在此處輸入圖片說明

完整復制|粘貼|運行 SQL:

with cte as (
select * from (
select 1  time, 'frank' user , 1 item union
select 2  time, 'frank' user , 0 item union
select 3  time, 'frank' user , 0 item union
select 4  time, 'frank' user , 0 item union
select 5  time, 'frank' user , 2 item union
select 6  time, 'alf' user ,   5 item union
select 7  time, 'alf' user ,   0 item union
select 8  time, 'alf' user ,   6 item union
select 9  time, 'alf' user ,   0 item union
select 10 time, 'alf' user ,   9) )
, good as (select * from cte where item<> 0) 
, bad as (select * from cte where item= 0) 


select *  from  good
union all
select 
     bad.time
    ,bad.user
    ,min(good.item ) 
from  bad 
left outer join  
    good on good.user=bad.user and good.time>bad.time 
group by
    1,2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM