Redshift JSON 数组的 Return 个元素在单独的行上
Return elements of Redshift JSON array on separate rows
我有一个 Redshift table,看起来像这样:
id | metadata
---------------------------------------------------------------------------
1 | [{"pet":"dog"},{"country":"uk"}]
2 | [{"pet":"cat"}]
3 | []
4 | [{"country":"germany"},{"education":"masters"},{"country":"belgium"}]
- 所有数组元素只有一个字段。
- 不能保证特定字段将出现在数组的任何元素中。
- 字段名可以在数组中重复
- 数组元素可以任意排列
我想找回看起来像这样的 table:
id | field | value
------------------------
1 | pet | dog
1 | country | uk
2 | pet | cat
4 | country | germany
4 | education | masters
4 | country | belgium
然后我可以将其与我对其余输入的查询结合起来 table。
我试过使用 Redshift JSON 函数,但是无法在 Redshift 中编写 functions/use loops/have 变量,我真的看不出有什么办法这个!
如果我能澄清任何其他问题,请告诉我。
多亏了这个启发blog post,我才能够设计出一个解决方案。这是:
创建查找 table 以有效地 'iterate' 每个数组的元素。此 table 中的行数已等于或大于数组的最大元素数。假设这是 4(可以使用 SELECT MAX(JSON_ARRAY_LENGTH(metadata)) FROM input_table
计算):
CREATE VIEW seq_0_to_3 AS
SELECT 0 AS i UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3
);
由此,我们可以为每个 JSON 元素创建一行:
WITH exploded_array AS (
SELECT id, JSON_EXTRACT_ARRAY_ELEMENT_TEXT(metadata, seq.i) AS json
FROM input_table, seq_0_to_3 AS seq
WHERE seq.i < JSON_ARRAY_LENGTH(metadata)
)
SELECT *
FROM exploded_array;
制作中:
id | json
------------------------------
1 | {"pet":"dog"}
1 | {"country":"uk"}
2 | {"pet":"cat"}
4 | {"country":"germany"}
4 | {"education":"masters"}
4 | {"country":"belgium"}
但是,我需要提取字段 names/values。由于我看不到使用 Redshift 的有限函数提取 JSON 字段名称的任何方法,我将使用正则表达式来执行此操作:
WITH exploded_array AS (
SELECT id, JSON_EXTRACT_ARRAY_ELEMENT_TEXT(metadata, seq.i) AS json
FROM input_table, seq_0_to_3 AS seq
WHERE seq.i < JSON_ARRAY_LENGTH(metadata)
)
SELECT id, field, JSON_EXTRACT_PATH_TEXT(json, field)
FROM (
SELECT id, json, REGEXP_SUBSTR(json, '[^{"]\w+[^"]') AS field
FROM exploded_array
);
CREATE VIEW seq_0_to_3
有通用版本。我们称它为 CREATE VIEW seq_0_to_n
。这可以由
生成
CREATE VIEW seq_0_to_n AS (
SELECT row_number() over (
ORDER BY TRUE)::integer - 1 AS i
FROM <insert_large_enough_table> LIMIT <number_less_than_table_entries>);
这有助于生成大型序列作为视图。
Redshift 现在可以将数组格式 [] 或 json 格式 {} 中的字符串视为可解析的 json 结构。首先,让我们根据您的数据制作一个临时 table:
create temporary table #t1 (id int, json_str varchar(100));
truncate table #t1;
insert into #t1 values (1, '[{"pet":"dog"},{"country":"uk"}]');
insert into #t1 values (2, '[{"pet":"cat"}]');
insert into #t1 values (3, '[]');
insert into #t1 values (4, '[{"country":"germany"},{"education":"masters"},{"country":"belgium"}]');
这个公共table表达式(cte)的创建将用于隐式地将json_str字段转换为SUPER类型的正式json结构。如果 table 的字段已经是 SUPER 类型,我们可以跳过这一步。
drop table if exists #t2;
create temporary table #t2 as
with cte as
(select
x.id,
json_parse(x.json_str) as json_str -- convert string to SUPER structure
from
#t1 x
)
select
x.id
,unnested
from
cte x, x.json_str as unnested -- an alias of cte and x.json_str is required!
order by
id
;
现在我们有一个 key/value 对的分解列表,可以轻松提取:
select
t2.id
,json_key -- this is the extracted key
,cast(json_val as varchar) as json_val -- eleminates the double quote marks
from
#t2 t2, unpivot t2.unnested as json_val at json_key --"at some_label" (e.g. json_key) will extract the key
order by
id
呈现信息的另一种方式是允许解析引擎将键转换为列。这不是您要的,但可能很有趣:
select
id
,cast(t2.unnested.country as varchar) -- data is already parsed into rows, so it's directly addressable now
,cast(t2.unnested.education as varchar)
,cast(t2.unnested.pet as varchar)
from
#t2 t2
;
如果您想了解更多信息,请使用搜索引擎搜索解析 SUPER 数据类型。如果数据在 Redshift table 中已经作为 SUPER 存在,后两个查询将针对 table 本机工作,不需要临时 table.
我有一个 Redshift table,看起来像这样:
id | metadata
---------------------------------------------------------------------------
1 | [{"pet":"dog"},{"country":"uk"}]
2 | [{"pet":"cat"}]
3 | []
4 | [{"country":"germany"},{"education":"masters"},{"country":"belgium"}]
- 所有数组元素只有一个字段。
- 不能保证特定字段将出现在数组的任何元素中。
- 字段名可以在数组中重复
- 数组元素可以任意排列
我想找回看起来像这样的 table:
id | field | value
------------------------
1 | pet | dog
1 | country | uk
2 | pet | cat
4 | country | germany
4 | education | masters
4 | country | belgium
然后我可以将其与我对其余输入的查询结合起来 table。
我试过使用 Redshift JSON 函数,但是无法在 Redshift 中编写 functions/use loops/have 变量,我真的看不出有什么办法这个!
如果我能澄清任何其他问题,请告诉我。
多亏了这个启发blog post,我才能够设计出一个解决方案。这是:
创建查找 table 以有效地 'iterate' 每个数组的元素。此 table 中的行数已等于或大于数组的最大元素数。假设这是 4(可以使用
SELECT MAX(JSON_ARRAY_LENGTH(metadata)) FROM input_table
计算):CREATE VIEW seq_0_to_3 AS SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 );
由此,我们可以为每个 JSON 元素创建一行:
WITH exploded_array AS ( SELECT id, JSON_EXTRACT_ARRAY_ELEMENT_TEXT(metadata, seq.i) AS json FROM input_table, seq_0_to_3 AS seq WHERE seq.i < JSON_ARRAY_LENGTH(metadata) ) SELECT * FROM exploded_array;
制作中:
id | json ------------------------------ 1 | {"pet":"dog"} 1 | {"country":"uk"} 2 | {"pet":"cat"} 4 | {"country":"germany"} 4 | {"education":"masters"} 4 | {"country":"belgium"}
但是,我需要提取字段 names/values。由于我看不到使用 Redshift 的有限函数提取 JSON 字段名称的任何方法,我将使用正则表达式来执行此操作:
WITH exploded_array AS ( SELECT id, JSON_EXTRACT_ARRAY_ELEMENT_TEXT(metadata, seq.i) AS json FROM input_table, seq_0_to_3 AS seq WHERE seq.i < JSON_ARRAY_LENGTH(metadata) ) SELECT id, field, JSON_EXTRACT_PATH_TEXT(json, field) FROM ( SELECT id, json, REGEXP_SUBSTR(json, '[^{"]\w+[^"]') AS field FROM exploded_array );
CREATE VIEW seq_0_to_3
有通用版本。我们称它为 CREATE VIEW seq_0_to_n
。这可以由
CREATE VIEW seq_0_to_n AS (
SELECT row_number() over (
ORDER BY TRUE)::integer - 1 AS i
FROM <insert_large_enough_table> LIMIT <number_less_than_table_entries>);
这有助于生成大型序列作为视图。
Redshift 现在可以将数组格式 [] 或 json 格式 {} 中的字符串视为可解析的 json 结构。首先,让我们根据您的数据制作一个临时 table:
create temporary table #t1 (id int, json_str varchar(100));
truncate table #t1;
insert into #t1 values (1, '[{"pet":"dog"},{"country":"uk"}]');
insert into #t1 values (2, '[{"pet":"cat"}]');
insert into #t1 values (3, '[]');
insert into #t1 values (4, '[{"country":"germany"},{"education":"masters"},{"country":"belgium"}]');
这个公共table表达式(cte)的创建将用于隐式地将json_str字段转换为SUPER类型的正式json结构。如果 table 的字段已经是 SUPER 类型,我们可以跳过这一步。
drop table if exists #t2;
create temporary table #t2 as
with cte as
(select
x.id,
json_parse(x.json_str) as json_str -- convert string to SUPER structure
from
#t1 x
)
select
x.id
,unnested
from
cte x, x.json_str as unnested -- an alias of cte and x.json_str is required!
order by
id
;
现在我们有一个 key/value 对的分解列表,可以轻松提取:
select
t2.id
,json_key -- this is the extracted key
,cast(json_val as varchar) as json_val -- eleminates the double quote marks
from
#t2 t2, unpivot t2.unnested as json_val at json_key --"at some_label" (e.g. json_key) will extract the key
order by
id
呈现信息的另一种方式是允许解析引擎将键转换为列。这不是您要的,但可能很有趣:
select
id
,cast(t2.unnested.country as varchar) -- data is already parsed into rows, so it's directly addressable now
,cast(t2.unnested.education as varchar)
,cast(t2.unnested.pet as varchar)
from
#t2 t2
;
如果您想了解更多信息,请使用搜索引擎搜索解析 SUPER 数据类型。如果数据在 Redshift table 中已经作为 SUPER 存在,后两个查询将针对 table 本机工作,不需要临时 table.