Snowflake: 如何在UNPIVOT中包含NULL值

huangapple go评论87阅读模式
英文:

Snowflake: How to include NULL value in the UNPIVOT

问题

要包括NULL值在UNPIVOT中,您可以使用Snowflake中的NVL函数来实现。以下是修改后的查询:

select Month, Name, NVL(value, NULL) as Value from 
TableName
    unpivot
    (
        Value 
        for Name in (Col_1,Col_2,Col_3,Col_4,Col_5)  
    ) u 

这将在结果中包括NULL值,如您所期望的那样:

Month    Name    Value
-----------------------
Jan      Col_1   NULL
Jan      Col_2   NULL
Jan      Col_3   1
Jan      Col_4   1
Jan      Col_5   1
英文:

Requirement: Include NULL values in the UNPIVOT

I have a table below:

Month   Col_1   Col_2   Col_3   Col_4   Col_5   
---------------------------------------------
Jan     NULL    NULL    1       1       1   

I want to unpivot this table

My query:

select Month, Name, value from 
TableName
    unpivot
    (
        Value 
        for Name in (Col_1,Col_2,Col_3,Col_4,Col_5)  
    ) u 

Result:

This results without the NULL values below:

Month    Name    Value
-----------------------
Jan      Col_3   1
Jan      Col_4   1
Jan      Col_5   1

Expected Result:

I want the NULLs to be included in the result

Month    Name    Value
-----------------------
Jan      Col_1   NULL
Jan      Col_2   NULL
Jan      Col_3   1
Jan      Col_4   1
Jan      Col_5   1

Any help would be appreciated in Snowflake

答案1

得分: 1

作为一种解决方法,如果您不希望在您的任何列中出现负数1。

with cte as (select 
                  month
                  ,ifnull(col_1,-1) col_1
                  ,ifnull(col_2,-1) col_2
                  ,ifnull(col_3,-1) col_3
                  ,ifnull(col_4,-1) col_4
                  ,ifnull(col_5,-1) col_5
                   from UNPIVOT_TEST
                                  )
                                  select 
                                  month
                                  ,name
                                  ,case when value=-1 then NULL else value end as value 
                                  from cte unpivot
                                  ( 
                                  value for name in ( col_1,col_2,col_3,col_4,col_5)
                                  );
英文:

as a workaround if you are not expecting negative 1 in any of your columns.

with cte as (select 
                  month
                  ,ifnull(col_1,-1) col_1
                  ,ifnull(col_2,-1) col_2
                  ,ifnull(col_3,-1) col_3
                  ,ifnull(col_4,-1) col_4
                  ,ifnull(col_5,-1) col_5
                   from UNPIVOT_TEST
                                  )
                                  select 
                                  month
                                  ,name
                                  ,case when value=-1 then NULL else value end as value 
                                  from cte unpivot
                                  ( 
                                  value for name in ( col_1,col_2,col_3,col_4,col_5)
                                  );

答案2

得分: 1

不要有别的内容。以下是翻译好的部分:

"Instead of using unpivot, you can use lateral flatten for this, by creating an object containing the key/values for your column names and values. This solution also dynamically assembles the column names you want to unpivot on, which may be helpful if you have a lot of columns to manage, or the source table might change over time."

"不要使用unpivot,您可以使用lateral flatten来实现此目标,方法是创建一个包含列名和值的键/值对对象。这种解决方案还会动态组装您要解构的列名,这在您需要管理大量列或源表可能会随时间变化时可能会有帮助。"

"First of all create the test data from your example:"

"首先,根据您的示例创建测试数据:"

"create or replace view test_data as
select *
from (VALUES ('Jan', NULL, NULL, 1, 1, 1) ) as
raw_data (Month, Col_1, Col_2, Col_3, Col_4, Col_5);"

"创建或替换测试数据视图test_data,如下所示:"
"从(VALUES('Jan',NULL,NULL,1,1,1))中选择*作为raw_data(Month,Col_1,Col_2,Col_3,Col_4,Col_5);"

"Then :"

"接下来:"

"with
kc_r1 as (
-- Return a 1 row result containing only the columns that you want to unpivot on.
-- 2 examples below."

"使用kc_r1作为:"
"-- 返回只包含您想要解构的列的1行结果。"
"-- 下面是2个示例。"

"select * EXCLUDE month from test_data limit 1"
"从test_data中选择* EXCLUDE month,限制为1行"
"-- select * ILIKE 'COL_%' from test_data limit 1 "

"kca as ("
"选择kca作为:"

" select
-- Create an array containing the column names required in the 'unpivot'
object_keys(object_construct_keep_null(*)) k_array
from kc_r1"

"从kc_r1中选择:"
"-- 创建一个包含在“unpivot”中需要的列名的数组"
"object_keys(object_construct_keep_null(*)) k_array"

"o as ("
"选择o作为:"

" select
month,
object_pick(object_construct_keep_null(test_data.*), kca.k_array) k_v
from kca, test_data)"

"从kca和test_data中选择:"
"month,"
"object_pick(object_construct_keep_null(test_data.*), kca.k_array) k_v"

"Select
month 'Month',
key 'Name',
value 'Value'
from kca, o, lateral flatten (input => k_v);"

"选择:"
"month 'Month',"
"key 'Name',"
"value 'Value'"
"from kca, o, lateral flatten (input => k_v);"

"Not sure if the column names in your example reflect your actual data but some of the column names your using are reserved words, which is not good practice."

"不确定您的示例中的列名是否反映了您的实际数据,但您使用的一些列名是保留字,这不是一个好的做法。"

英文:

Instead of using unpivot, you can use lateral flatten for this, by creating an object containing the key/values for your column names and values. This solution also dynamically assembles the column names you want to unpivot on, which may be helpful if you have a lot of columns to manage, or the source table might change over time.

First of all create the test data from your example:

create or replace view test_data as
select *
from (VALUES ('Jan', NULL, NULL, 1, 1, 1) ) as 
               raw_data (Month, Col_1, Col_2, Col_3, Col_4, Col_5);

Then :

with 
kc_r1 as (
         -- Return a 1 row result containing only the columns that you want to unpivot on. 
         -- 2 examples below.
         select * EXCLUDE month from test_data limit 1
         -- select * ILIKE 'COL_%' from test_data limit 1 
         ),
kca as (
   select 
      -- Create an array containing the column names required in the 'unpivot'
      object_keys(object_construct_keep_null(*)) k_array
   from kc_r1
),
o as (
   select 
      month,
      object_pick(object_construct_keep_null(test_data.*), kca.k_array) k_v 
   from kca, test_data)
Select 
   month "Month",
   key "Name",
   value "Value"
from kca, o, lateral flatten (input => k_v)
;

Not sure if the column names in your example reflect your actual data but some of the column names your using are reserved words, which is not good practice.

答案3

得分: 0

我相信这将在Snowflake中起作用(尽管我假设concat()是一个有效的函数)

with numbers as (
 select 1 as n union all
 select 2 as n union all
 select 3 as n union all
 select 4 as n union all
 select 5 as n
 )
select
  t.Month
, concat('col_', numbers.n) as name
, case
    when numbers.n = 1 then col_1
    when numbers.n = 2 then col_2
    when numbers.n = 3 then col_3
    when numbers.n = 4 then col_4
    when numbers.n = 5 then col_5
  end as value
from tablename t
cross join numbers

跨连接到5行执行所需的行扩展,然后我们可以使用case表达式将所有值放入一个列中。如果无法使用连接方法,您还可以为名称使用case表达式。

英文:

I believe this will work in snowflake (although I'm assuming concat() is a valid function)

with numbers as (
 select 1 as n union all
 select 2 as n union all
 select 3 as n union all
 select 4 as n union all
 select 5 as n
 )
select
  t.Month
, concat('col_', numbers.n) as name
, case
    when numbers.n = 1 then col_1
    when numbers.n = 2 then col_2
    when numbers.n = 3 then col_3
    when numbers.n = 4 then col_4
    when numbers.n = 5 then col_5
  end as value
from tablename t
cross join numbers 

The cross join to 5 rows does the needed row expansion, then we can use a case expression to put all values into 1 column. You could also use a case expression for name if you can't use the concatenation approach.

huangapple
  • 本文由 发表于 2023年8月10日 11:10:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76872419.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定