如何将动态 json 键展平为 BigQuery 中的列?

问题描述

这是原始的 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.typerrkeysrr 中的 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 等。

  1. 如何将动态 keysrr 提取到列中?
  2. 如何不硬编码 sql 以获得 scp

测试答案时,请随意删除 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 结构 - 输出为

enter image description here

,

具有一组非封闭键的 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 对象施法者就会为您处理所有其他事情!