如何将jsonMySQL数据转换成行和列

How to convert json MySQL data into rows and column

我有 mysql table 这样的包含 id 和 json 类型的列:

id value
1 {"sys": "20", "dia": "110"}
2 {"bpm": "200"}
3 {"bpm": "123", "sys": "1", "dia": ""}

现在,我想要一个 MySQL 查询,其数据应如下所示,其中 id、val1 将包含 json 数据的键,而 val2 将包含相应键的值:

id val1 val2
1 sys 20
1 dia 110
2 bpm 200
3 bpm 123
3 sys 1
3 dia

注意:我使用的是 MySQL 5.7 版本,JSON 对象中的键是不固定的。它可以是任何数字。

我想知道如何使用 MySQL 查询

实现此目的

提前致谢!!!

CREATE TABLE test (id INT, value JSON);
INSERT INTO test VALUES
(1,   '{"sys": "20", "dia": "110"}'),
(2,   '{"bpm": "200"}'),
(3,   '{"bpm": "123", "sys": "1", "dia": ""}');
SELECT id, CAST(value AS CHAR) value FROM test;
id value
1 {"dia": "110", "sys": "20"}
2 {"bpm": "200"}
3 {"bpm": "123", "dia": "", "sys": "1"}
CREATE PROCEDURE parse_json ()
BEGIN
DECLARE counter INT DEFAULT 0;
CREATE TEMPORARY TABLE tmp1 (id INT, all_keys JSON)
SELECT id, JSON_KEYS(value) all_keys
FROM test;
CREATE TEMPORARY TABLE tmp2 (id INT, one_key VARCHAR(255)) ENGINE = Memory;
REPEAT
    INSERT INTO tmp2
    SELECT id, JSON_EXTRACT(all_keys, CONCAT('$[',counter,']')) one_key
    FROM tmp1
    HAVING one_key IS NOT NULL;
    SET counter := counter + 1;
UNTIL NOT ROW_COUNT() END REPEAT;
SELECT id, 
       CAST(JSON_UNQUOTE(tmp2.one_key) AS CHAR) val1, 
       CAST(JSON_UNQUOTE(JSON_EXTRACT(test.value, CONCAT('$.', tmp2.one_key))) AS CHAR) val2
FROM test
JOIN tmp2 USING (id)
ORDER BY 1,2;
DROP TEMPORARY TABLE tmp1;
DROP TEMPORARY TABLE tmp2;
END
CALL parse_json
id val1 val2
1 dia 110
1 sys 20
2 bpm 200
3 bpm 123
3 dia
3 sys 1

db<>fiddle here

如果具有 JSON 值的列的数据类型为 VARCHAR/TEXT,则数据应 NOT 包含 JSON 值中的重复键。

我能够找到下面的 sql 查询,它将 return 我的数据:

select id as Id
,JSON_UNQUOTE(JSON_EXTRACT(JSON_KEYS(value), CONCAT('$[', idx , ']'))) as val1
,JSON_UNQUOTE(JSON_EXTRACT(ic1.value, CONCAT('$.',JSON_EXTRACT(JSON_KEYS(value), CONCAT('$[', idx , ']'))))) as val2
from test as ic1
INNER JOIN (  
   SELECT 0 as idx UNION ALL 
   SELECT 1 as idx UNION ALL 
   SELECT 2 as idx UNION ALL 
   SELECT 3 as idx UNION ALL
   SELECT 4 as idx UNION ALL 
   SELECT 5 as idx UNION ALL
   SELECT 6 as idx UNION ALL
   SELECT 7 as idx UNION ALL
   SELECT 8 
  ) AS Indices 
ON Indices.idx < JSON_LENGTH(JSON_KEYS(value))
ORDER BY id;