'SNOWFLAKE : read a VARIANT column as a table?
We have the following table
WITH fake_data(columnA, columnB, columnC) as (
select * from values
(1, 'hello1', 'world18'),
(1, 'hello2', 'world27'),
(2, 'hello9', 'world36')
(3, NULL, 'world35')
(10, 'hello13', 'world5')
)
We convert the entire table into a single column that has a JSON-like structure
CREATE OR REPLACE TEMPORARY TABLE LISTE_JSON (V variant)
AS
WITH COLONNE_KEY
AS (
SELECT
ROW_NUMBER () OVER (ORDER BY columnA DESC) KEY_AUTO
,A.*
FROM fake_data A
),
COLONNE_OBJECT
AS (
SELECT
object_agg(
TO_CHAR(KEY_AUTO ) ,
object_construct(
'columnA', IFNULL(columnA,''),
'columnB', IFNULL(columnB,''),
'columnC', IFNULL(columnC,''),
)
)AS COLONNE_OBJECT
FROM COLONNE_KEY
)
SELECT *
FROM COLONNE_OBJECT;
So far everything is going well.
Now how do I read the variant column through a SELECT and see it as a table, as it was at the beginning?
Ex:
SELECT *
FROM LISTE_JSON
COLUMNA COLUMNB COLUMNC
1 hello1 world18
1 hello2 world27
2 hello9 world36
3 '' world35
10 hello13 world5
Solution 1:[1]
You can ether use PIVOT to pull with parts, or you can hand roll the pivot via GROUP BY
SELECT
columna
,max(iff(columnb='hello1', columnc, null)) as hello1
,max(iff(columnb='hello2', columnc, null)) as hello2
,max(iff(columnb='hello3', columnc, null)) as hello3
from table
group by 1 order by 1;
So lets start with working "example code"
WITH fake_data(columnA, columnB, columnC) as (
select * from values
(1, 'hello1', 'world18'),
(1, 'hello2', 'world27'),
(2, 'hello9', 'world36'),
(3, NULL, 'world35'),
(10, 'hello13', 'world5')
), COLONNE_KEY AS (
SELECT
ROW_NUMBER () OVER (ORDER BY columnA DESC) KEY_AUTO
,A.*
FROM fake_data A
), COLONNE_OBJECT AS (
SELECT
object_agg( KEY_AUTO::text ,
object_construct('columnA', IFNULL(columnA::text,''),
'columnB', IFNULL(columnB::text,''),
'columnC', IFNULL(columnC::text,'')
)
)AS COLONNE_OBJECT
FROM COLONNE_KEY
)
SELECT *
FROM COLONNE_OBJECT;
gives:
COLONNE_OBJECT |
---|
{ "1": { "columnA": "10", "columnB": "hello13", "columnC": "world5" }, "2": { "columnA": "3", "columnB": "", "columnC": "world35" }, "3": { "columnA": "2", "columnB": "hello9", "columnC": "world36" }, "4": { "columnA": "1", "columnB": "hello1", "columnC": "world18" }, "5": { "columnA": "1", "columnB": "hello2", "columnC": "world27" } } |
which you would like to get back into it original table form
thus
SELECT
f.value:"columnA"::number as columna,
f.value:"columnB"::text as columnb,
f.value:"columnC"::text as columnc
FROM COLONNE_OBJECT, table(flatten(input=>colonne_object)) f;
gives you back
COLUMNA | COLUMNB | COLUMNC |
---|---|---|
10 | hello13 | world5 |
3 | <empty string> | world35 |
2 | hello9 | world36 |
1 | hello1 | world18 |
1 | hello2 | world27 |
and the empty string
can be swapped back in via
nullif(f.value:"columnB"::text,'') as columnb,
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |