问题描述
这是原始的 JSON 结构:
{
"tt": [{
"Box": {
"type": "A"
},"rr": {...}
},{
"Box": {
"type": "B"
},{
"Box": {
"type": "C"
},"rr": {...}
}]
}
然后我用下面的sql命令得到tt
结构
with t1 as (
SELECT
rate_card,JSON_EXTRACT_ARRAY(rate_card,'$.tt') as rr,FROM `original_table_temp`
)
上一个 JSON 结构中的 rr
JSON 结构如下所示
{
"rr": {
"10": { <-------------------------
"tils": {
"mdd": {
"df": {
"tif": {
"sc": 17.85,<------------------
"evr": [
{
"p": 16.35,<---------------------
"t": null,"nr?": false
}
]
}
}
},"11": {...},"12": {...},...
}
}
以上所有 sql 命令都在 BigQuery 中执行。
我想将 Box.type
、rr
的 keys
(rr
中的 10、11、12 等)放入一列。
keys
旁边的列是 sc
& p
最终表格的输出如下:
+------------+---------+---------------+
| Box.type| rr | sc | p |
+------------+-------------------------+
| A | 10 | 17.85 | 16.35 |
| A | 11 |some value| .... |
......
| C | 12 | ..... | ......|
+------------+----------------------------+
目前,我设法通过在 sql BigQuery 中硬编码来获得 sc
值。见下文:
SELECT
JSON_EXTRACT_SCALAR(rr_2,'$.rr.10.tils.mdd.df.tif.sc') AS sc,FROM t1,UNnesT(rr) rr_2
上述方法效率不高,因为有很多 keys
,例如 10、11、12 等。
测试答案时,请随意删除 JSON 示例中的 <----------
。
这是一篇长文。如果您需要更多信息,请告诉我。
感谢您的耐心和时间。
解决方法
考虑以下
execute immediate (
select string_agg("select " || key || ''' key,JSON_EXTRACT_SCALAR(rr_2,'$.rr.''' || key || '''.tils.mdd.df.tif.sc') AS sc,'$.rr.''' || key || '''.tils.mdd.df.tif.evr[0].p') AS p
from `project.dataset.table`'''," union all ")
from `project.dataset.table`,unnest(regexp_extract_all(regexp_replace(JSON_EXTRACT(rr_2,'$.rr'),r':{.*?}+',''),r'"(.*?)"')) key
);
如果要应用于原始示例中的 rr JSON
结构 - 输出为
具有一组非封闭键的 JSON 对象不能很好地映射到面向 SQL 表的域。
解决此问题的一种方法是将 abc:folder/1.txt:32:abc is here
bbc:folder/ss/2.txt:2: bbc is here
之类的结构化 JSON 数据转换为 {key1: {},key2: {},...}
之类的数据。
使用 BigQuery Javascript UDF...
在 Javascript 域中可以轻松实现这种转换[{key1,...},{key2,...]
这是解包 CREATE TEMPORARY FUNCTION extract_tt(json STRING)
RETURNS STRUCT<
tt ARRAY<STRUCT<
box STRUCT<
type STRING
>,rr ARRAY<STRUCT<
key STRING,tils STRUCT<
mdd STRUCT<
df STRUCT<
tif STRUCT<
sc FLOAT64,evr ARRAY<STRUCT<
p FLOAT64,t STRING,nr BOOL
>>
>
>
>
>
>>
>>
>
DETERMINISTIC
LANGUAGE js
AS
r"""
try {
return JSON.parse(json,(key,value) => {
if (key === 'rr' && value !== null && typeof value === 'object')
return Object.keys(value).map(key => ({ key,...value[key] }));
else
return value;
});
}
catch {}
""";
WITH extracted AS (
SELECT extract_tt(json).*
FROM UNNEST([
'{"tt":[{"box":{"type":"A"},"rr":{"10":{"tils":{"mdd":{"df":{"tif":{"sc":17.85,"evr":[{"p":16.35,"t":null,"nr":false}]}}}}},"11":{}}},{"box":{"type":"B"},"rr":{}},{"box":{"type":"C"},"rr":{"12":{"tils":{"mdd":{"df":{"tif":{"sc":99}}}}}}}]}'
]) AS json
)
SELECT box.type,key,tils.mdd.df.tif.sc,tils.mdd.df.tif.evr[OFFSET(0)].p
FROM extracted,UNNEST(tt),UNNEST(rr);
的结果,它可以平滑地表示 rr
... 的动态键的任何程度的变化
行 | 类型 | 键 | sc | p |
---|---|---|---|---|
1 | A | 10 | 17.85 | 16.35 |
2 | A | 11 | 空 | 空 |
3 | C | 12 | 99.0 | 空 |
请注意,UDF 的返回类型经过精心设计以从 JSON 域映射到 SQL 域。只要类型匹配,BigQuery 对象施法者就会为您处理所有其他事情!