【问题标题】:Expand JSON with unknown keys to rows with MySQL JSON_TABLE使用 MySQL JSON_TABLE 将带有未知键的 JSON 扩展到行
【发布时间】:2021-04-08 16:44:02
【问题描述】:

我有一个 MySQL 8.0.22 JSON 列,其中包含带有事先不知道的键的对象:

'{"x": 1, "y": 2, "z": 3}'
'{"e": 4, "k": 5}'

我想使用JSON_TABLE 将这些值扩展为包含键值对的多行:

key value
x 1
y 2
z 3
e 4
k 5

当然,困难在于密钥是未知的先验。我想出的最好的事情是......


SET @json_doc = '{"x": 1, "y": 2, "z": 3}';

SELECT a.seq, b.k, a.v

    FROM

    JSON_TABLE(
        @json_doc,
        "$.*"
        COLUMNS(
            seq FOR ordinality,
            v INT PATH "$"
        )
    ) AS a,

    JSON_TABLE(
        JSON_KEYS(@json_doc),
        "$[*]"
        COLUMNS(
            seq FOR ordinality,
            k CHAR(1) PATH "$"
        )
    ) AS b

    WHERE a.seq = b.seq;

这感觉很奇怪,因为它使用了两个JSON_TABLE 调用,对值和键进行交叉连接,然后保持对齐。我想找到一个像这样更简单的查询...

SELECT a.seq, b.k, a.v

    FROM
    
    JSON_TABLE(
        @json_doc,
        "$.*"
        COLUMNS(
            seq FOR ordinality,
            k CHAR(1) PATH "?"  -- <-- what do I put here to find each key?
            v INT PATH "$"
        )
    ) AS a,

我知道这个问题可能可以通过 CTE 或数字表和 JSON_EXTRACT 来解决。但是,如果可能的话,我想找到一些高性能和可读的东西。

【问题讨论】:

    标签: mysql sql json mysql-8.0


    【解决方案1】:

    您可以通过ROW_NUMBER()窗口函数使用enumarete,同时通过使用JSON_KEYS()确定键值,然后使用JSON_EXTRACT()从我们得到的数组中提取相应的键,例如

    WITH k AS
    (
    SELECT *, 
           ROW_NUMBER() OVER(PARTITION BY `jsdata` ORDER BY value DESC) AS rn,
           JSON_KEYS(`jsdata`) AS jk
      FROM `tab` AS t
      JOIN JSON_TABLE(`jsdata`,'$.*' COLUMNS (value INT PATH '$')) j
    )
    SELECT JSON_UNQUOTE(JSON_EXTRACT(jk, CONCAT('$[',rn-1,']'))) AS "key", 
           value
      FROM k
    

    使用以下查询更直接

    SELECT JSON_UNQUOTE(
           JSON_EXTRACT(JSON_KEYS(`jsdata`), 
                        CONCAT('$[',
                        ROW_NUMBER() OVER(PARTITION BY `jsdata` ORDER BY value DESC)-1,
                        ']'))
                       ) AS "key", value
      FROM `tab` AS t
      JOIN JSON_TABLE(`jsdata`,'$.*' COLUMNS (value INT PATH '$')) j
    

    Demo

    【讨论】:

      【解决方案2】:

      在将JSON_KEYS 作为行后,尝试直接执行JSON_EXTRACT

        WITH j AS (
            SELECT CAST('{"a": 1, "b": "-1", "c": null}' AS JSON) o UNION ALL
            SELECT CAST('{"x": 2, "y": "-2", "z": null}' AS JSON)
        )
      SELECT k, JSON_EXTRACT(j.o, CONCAT('$."', jt.k, '"')) v
        FROM j
           , JSON_TABLE(JSON_KEYS(o), '$[*]' COLUMNS (k VARCHAR(200) PATH '$')) jt;
      

      Barbaros 的回答可以用你提供的演示数据解决你的问题,但是如果你的 json 对象在不同的​​键下具有相同的值,它可能无法得到你想要的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-01-29
        • 2019-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-22
        • 1970-01-01
        相关资源
        最近更新 更多