我有一个看起来像这样的Redshift表:
id | metadata
---------------------------------------------------------------------------
1 | [{"pet":"dog"},{"country":"uk"}]
2 | [{"pet":"cat"}]
3 | []
4 | [{"country":"germany"},{"education":"masters"},{"country":"belgium"}]
我想要找回一个看起来像这样的表:
id | field | value
------------------------
1 | pet | dog
1 | country | uk
2 | pet | cat
4 | country | germany
4 | education | masters
4 | country | belgium
然后我可以将它与我对输入表其余部分的查询结合起来。
我尝试过使用Redshift JSON函数,但是无法在Redshift中编写函数/使用循环/有变量,我真的看不到这样做的方法!
如果我能澄清其他任何内容,请告诉我。
答案 0 :(得分:5)
感谢blog post的启发,我已经能够制定出一个解决方案。这是:
创建一个查找表,以便有效地“重复”'在每个数组的元素。此表中的行数等于或大于数组的最大元素数。我们假设这是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"}
但是,我需要提取字段名称/值。由于我无法使用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
);
答案 1 :(得分:1)
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>);
这有助于生成大型序列作为视图。