Snowflake: 如何在UNPIVOT中包含NULL值

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

Snowflake: How to include NULL value in the UNPIVOT

问题

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

  1. select Month, Name, NVL(value, NULL) as Value from
  2. TableName
  3. unpivot
  4. (
  5. Value
  6. for Name in (Col_1,Col_2,Col_3,Col_4,Col_5)
  7. ) u

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

  1. Month Name Value
  2. -----------------------
  3. Jan Col_1 NULL
  4. Jan Col_2 NULL
  5. Jan Col_3 1
  6. Jan Col_4 1
  7. Jan Col_5 1
英文:

Requirement: Include NULL values in the UNPIVOT

I have a table below:

  1. Month Col_1 Col_2 Col_3 Col_4 Col_5
  2. ---------------------------------------------
  3. Jan NULL NULL 1 1 1

I want to unpivot this table

My query:

  1. select Month, Name, value from
  2. TableName
  3. unpivot
  4. (
  5. Value
  6. for Name in (Col_1,Col_2,Col_3,Col_4,Col_5)
  7. ) u

Result:

This results without the NULL values below:

  1. Month Name Value
  2. -----------------------
  3. Jan Col_3 1
  4. Jan Col_4 1
  5. Jan Col_5 1

Expected Result:

I want the NULLs to be included in the result

  1. Month Name Value
  2. -----------------------
  3. Jan Col_1 NULL
  4. Jan Col_2 NULL
  5. Jan Col_3 1
  6. Jan Col_4 1
  7. Jan Col_5 1

Any help would be appreciated in Snowflake

答案1

得分: 1

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

  1. with cte as (select
  2. month
  3. ,ifnull(col_1,-1) col_1
  4. ,ifnull(col_2,-1) col_2
  5. ,ifnull(col_3,-1) col_3
  6. ,ifnull(col_4,-1) col_4
  7. ,ifnull(col_5,-1) col_5
  8. from UNPIVOT_TEST
  9. )
  10. select
  11. month
  12. ,name
  13. ,case when value=-1 then NULL else value end as value
  14. from cte unpivot
  15. (
  16. value for name in ( col_1,col_2,col_3,col_4,col_5)
  17. );
英文:

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

  1. with cte as (select
  2. month
  3. ,ifnull(col_1,-1) col_1
  4. ,ifnull(col_2,-1) col_2
  5. ,ifnull(col_3,-1) col_3
  6. ,ifnull(col_4,-1) col_4
  7. ,ifnull(col_5,-1) col_5
  8. from UNPIVOT_TEST
  9. )
  10. select
  11. month
  12. ,name
  13. ,case when value=-1 then NULL else value end as value
  14. from cte unpivot
  15. (
  16. value for name in ( col_1,col_2,col_3,col_4,col_5)
  17. );

答案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:

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

Then :

  1. with
  2. kc_r1 as (
  3. -- Return a 1 row result containing only the columns that you want to unpivot on.
  4. -- 2 examples below.
  5. select * EXCLUDE month from test_data limit 1
  6. -- select * ILIKE 'COL_%' from test_data limit 1
  7. ),
  8. kca as (
  9. select
  10. -- Create an array containing the column names required in the 'unpivot'
  11. object_keys(object_construct_keep_null(*)) k_array
  12. from kc_r1
  13. ),
  14. o as (
  15. select
  16. month,
  17. object_pick(object_construct_keep_null(test_data.*), kca.k_array) k_v
  18. from kca, test_data)
  19. Select
  20. month "Month",
  21. key "Name",
  22. value "Value"
  23. from kca, o, lateral flatten (input => k_v)
  24. ;

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()是一个有效的函数)

  1. with numbers as (
  2. select 1 as n union all
  3. select 2 as n union all
  4. select 3 as n union all
  5. select 4 as n union all
  6. select 5 as n
  7. )
  8. select
  9. t.Month
  10. , concat('col_', numbers.n) as name
  11. , case
  12. when numbers.n = 1 then col_1
  13. when numbers.n = 2 then col_2
  14. when numbers.n = 3 then col_3
  15. when numbers.n = 4 then col_4
  16. when numbers.n = 5 then col_5
  17. end as value
  18. from tablename t
  19. cross join numbers

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

英文:

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

  1. with numbers as (
  2. select 1 as n union all
  3. select 2 as n union all
  4. select 3 as n union all
  5. select 4 as n union all
  6. select 5 as n
  7. )
  8. select
  9. t.Month
  10. , concat('col_', numbers.n) as name
  11. , case
  12. when numbers.n = 1 then col_1
  13. when numbers.n = 2 then col_2
  14. when numbers.n = 3 then col_3
  15. when numbers.n = 4 then col_4
  16. when numbers.n = 5 then col_5
  17. end as value
  18. from tablename t
  19. 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:

确定