使用任意键解析 JSON 个值

Parse JSON values with arbitrary keys

我在 table 中有一列是 JSON 字符串。这些字符串的一部分具有以下格式:

{
    ...
    "rules": {
        "rule_1": {
            "results": [],
            "isTestMode": true
        },
        "rule_2": {
            "results": [],
            "isTestMode": true
        },
        "rule_3": {
            "results": [
                {
                    "required": true,
                    "amount": 99.31
                }
            ],
            "isTestMode": true
        },
        "rule_4": {
            "results": [],
            "isTestMode": false
        },
        ...
    }
    ...
}

在这个嵌套的 "rules" 对象中,我想 return true if results[0]["required"] = true AND "isTestMode" = false 对于任何规则。问题是 "rule_1""rule_2"、... "rule_x" 可以有事先不知道的任意名称。

是否可以编写一个查询来遍历“规则”中的所有键并检查其中是否有任何一个符合此条件?还有其他方法可以实现吗?

如果事先知道密钥,那么我可以这样做:

WHERE 
    (JSON_ARRAY_LENGTH(JSON_EXTRACT(json, '$.rules.rule_1.results')) = 1 
        AND JSON_EXTRACT_SCALAR(json, '$rules.rule_1.results[0].required') = 'true' 
        AND JSON_EXTRACT_SCALAR(json, '$rules.rule_1.isTestMode') = 'false')
    OR (JSON_ARRAY_LENGTH(JSON_EXTRACT(json, '$.rules.rule_2.results')) = 1 
        AND JSON_EXTRACT_SCALAR(json, '$rules.rule_2.results[0].required') = 'true' 
        AND JSON_EXTRACT_SCALAR(json, '$rules.rule_2.isTestMode') = 'false')
    OR ...

我可以用正则表达式解决这个问题。不理想,仍然想知道这是否可以使用内置的 JSON 函数来完成。

WHERE REGEXP_LIKE(json, '.*{"results":\[{"required":true,"amount":\d+.\d+"}],"isTestMode":false}.*')

您可以提取rules 属性并将其转换为MAP(varchar, json)并进行处理:

WITH dataset AS (
    SELECT * FROM (VALUES   
       (JSON '{
    "rules": {
        "rule_1": {
            "results": [],
            "isTestMode": true
        },
        "rule_2": {
            "results": [],
            "isTestMode": true
        },
        "rule_3": {
            "results": [
                {
                    "required": true,
                    "amount": 99.31
                }
            ],
            "isTestMode": true
        },
        "rule_4": {
            "results": [],
            "isTestMode": false
        }
    }
}')
 ) AS t (json_value))

select cardinality(
    filter(
        map_values(cast(json_extract(json_value, '$.rules') as MAP(varchar, json))), -- trasnform into MAP and get it's values
        js -> cast(json_extract(js, '$.isTestMode') as BOOLEAN) -- check isTestMode
            AND cast(json_extract(js, '$.results[0].required') as BOOLEAN)  -- check required of first element of `results`
    )) > 0
from dataset

这将为提供的数据提供 true