将 bigquery json 字符串转换为列
Posted
技术标签:
【中文标题】将 bigquery json 字符串转换为列【英文标题】:convert bigquery json string to columns 【发布时间】:2019-08-30 13:56:39 【问题描述】:对于以字符串形式出现的 json 数据,我希望使用 JSON_EXTRACT_SCALAR 之类的内容,但结果列的数量可以灵活调整。
这里是示例数据——不同的行可以有不同的列名,json可以嵌套:
WITH `my_table` AS (
SELECT '"sku_types":"\"id\":\"5433306\",\"product_code\":\"adfklj_ewkj\"","additional_info":"Face 30 ml","stock_level":"20+"' as json_string
union all
SELECT '"additional_info":"Face 100 ml","offer_info":"30%"' as json_string
)
SELECT *
from my_table;
我希望将这些数据提取到单独的列中:sku_types.id, sku_types.product_code, additional_info, stock_level, offer_info
。
这可以在 SQL 中完成还是需要 javascript?
我事先不知道 json 字段的名称,所以我无法使用 JSON_EXTRACT_SCALAR
或 JSON_EXTRACT
来做到这一点。
【问题讨论】:
【参考方案1】:以下 BigQuery 标准 SQL 示例
#standardSQL
CREATE TEMPORARY FUNCTION parseJson(y STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS """
var z = new Array();
processKey(JSON.parse(y), '');
function processKey(node, parent)
Object.keys(node).map(function(key)
value = node[key].toString();
if (value !== '[object Object]')
if (parent !== '' && parent.substr(parent.length-1) !== '.')
z.push(parent + '.' + key + ':' + value)
else
z.push(key + ':' + value)
else
if (parent !== '' && parent.substr(parent.length-1) !== '.') parent += '.';
processKey(node[key], parent + key);
;
);
;
return z
""";
WITH `my_table` AS (
SELECT 1 id, '"sku_types":"id":"5433306","product_code":"adfklj_ewkj","additional_info":"Face 30 ml","stock_level":"20+"' AS json_string UNION ALL
SELECT 2, '"additional_info":"Face 100 ml","offer_info":"30%"' AS json_string
)
SELECT id,
ARRAY(
SELECT AS STRUCT SPLIT(kv, ':')[OFFSET(0)] key, SPLIT(kv, ':')[SAFE_OFFSET(1)] value
FROM UNNEST(parseJson(json_string)) kv
) params
FROM my_table
结果
Row id params.key params.value
1 1 sku_types.id 5433306
sku_types.product_code adfklj_ewkj
additional_info Face 30 ml
stock_level 20+
2 2 additional_info Face 100 ml
offer_info 30%
正如您所看到的,而不是将所有可能的属性解析为单独的列(这在此处完全不可能 - 除非您事先知道它们) - 上述方法将它们展平为参数数组中的键:值对
注意:在上面的示例中,我使用:
来构造键:值对,然后将它们拆分。如果您希望值具有此字符 - 您可以调整代码而不是 :
使用更独特的东西 - 例如 :::::::
快速更新地址评论: ...问题是一些json值是空的,在这种情况下它会抛出错误
#standardSQL
CREATE TEMPORARY FUNCTION parseJson(y STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS """
var z = new Array();
processKey(JSON.parse(y), '');
function processKey(node, parent)
Object.keys(node).map(function(key)
if (!node[key])
value = 'n/a'
else
value = node[key].toString();
if (value !== '[object Object]')
if (parent !== '' && parent.substr(parent.length-1) !== '.')
z.push(parent + '.' + key + ':' + value)
else
z.push(key + ':' + value)
else
if (parent !== '' && parent.substr(parent.length-1) !== '.') parent += '.';
processKey(node[key], parent + key);
;
);
;
return z
""";
WITH `my_table` AS (
SELECT 1 id, '"sku_types":"id":"5433306","product_code":"adfklj_ewkj","additional_info":"Face 30 ml","stock_level":"20+"' AS json_string UNION ALL
SELECT 2, '"additional_info":"Face 100 ml","offer_info":"30%"' AS json_string union all
SELECT 3 as id , '"offer_info":"30%", "price":null' AS json_string
)
SELECT id,
ARRAY(
SELECT AS STRUCT SPLIT(kv, ':')[OFFSET(0)] key, SPLIT(kv, ':')[SAFE_OFFSET(1)] value
FROM UNNEST(parseJson(json_string)) kv
) params
FROM my_table
结果
Row id params.key params.value
1 1 sku_types.id 5433306
sku_types.product_code adfklj_ewkj
additional_info Face 30 ml
stock_level 20+
2 2 additional_info Face 100 ml
offer_info 30%
3 3 offer_info 30%
price n/a
如你所见 - 我用 'n/a'
替换空值,但你可以应用任何你想要的逻辑
【讨论】:
这很有效,谢谢!我唯一的问题是某些 json 值为 null,在这种情况下它会抛出错误:... SELECT 3 as id , '"offer_info":"30%", "price":null' AS json_string ) 。 .. 我将在一天后检查这个案例,并更新我的答案以解决空问题:o) 感谢您的帮助! :) 当然,正如预期的那样 :o) - 下一篇文章/问题见!以上是关于将 bigquery json 字符串转换为列的主要内容,如果未能解决你的问题,请参考以下文章