BigQuery 标准 SQL 如下
见Enabling Standard SQL和User-Defined Functions
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]') {
z.push(key)
} else {
if (parent !== '' && parent.substr(parent.length-1) !== '.') {parent += '.'};
processKey(node[key], parent + key);
};
});
};
return z
""";
WITH theTable AS (
SELECT '{"json":{"A":"1"}}' AS json UNION ALL
SELECT '{"json":{"B":"1"}}' AS json UNION ALL
SELECT '{"json":{"B":"1","C":"1"}}' AS json
)
SELECT key, COUNT(1) AS `count`
FROM theTable, UNNEST(parseJson(json)) AS key
GROUP BY key
ORDER BY 2 DESC
输出:
key count
B 2
A 1
C 1
注意:parseJson UDF 足够通用,可以处理任何 json,因此您可以例如尝试使用以下输入的上述代码,它仍然可以工作:
WITH theTable AS (
SELECT '{"json":{"A":"1"}}' AS json UNION ALL
SELECT '{"json":{"B":"1"}}' AS json UNION ALL
SELECT '{"json":{"B":"1","C":"1"}}' AS json UNION ALL
SELECT '{"A":"1"}' AS json UNION ALL
SELECT '{"B":"1"}' AS json UNION ALL
SELECT '{"B":"1","C":"1"}' AS json
)
输出:
key count
B 4
A 2
C 2
为 BigQuery Legacy SQL 添加了版本
为了简单起见,在这里展示和进一步测试 - 我在这里使用的是旧版 SQL UDF 的 inline version。旧版 SQL 中的 Inline version 不受官方支持 - 因此,如果它适用于您 - 您需要稍微改造一下 - 有关 BigQuery 旧版 SQL 中 UDF 的详细信息,请参阅 BigQuery User-Defined Functions
SELECT key, COUNT(1) as cnt
FROM JS((
SELECT json FROM
(SELECT '{"json":{"A":"1"}}' AS json),
(SELECT '{"json":{"B":"1"}}' AS json),
(SELECT '{"json":{"B":"1","C":"1"}}' AS json),
(SELECT '{"A":"1"}' AS json),
(SELECT '{"B":"1"}' AS json),
(SELECT '{"B":"1","C":"1"}' AS json)
),
json, // Input columns
"[{name: 'parent', type:'string'}, // Output schema
{name: 'key', type:'string'},
{name: 'value', type:'string'}]",
"function(r, emit) { // The function
processKey(JSON.parse(r.json), '');
function processKey(node, parent) {
Object.keys(node).map(function(key) {
value = node[key].toString();
if (value !== '[object Object]') {
emit({parent:parent, key:key, value:value});
} else {
if (parent !== '' && parent.substr(parent.length-1) !== '.') {parent += '.'};
processKey(node[key], parent + key);
};
});
};
}"
)
GROUP BY key
ORDER BY cnt DESC