MySQL 5.7 - Select JSON 文档为 Table
MySQL 5.7 - Select JSON document as Table
我有以下 JSON 数据格式,其中包含简单的 Key/Value 对数据。
CREATE TABLE test_table (id INT, jdoc JSON);
INSERT INTO test_table VALUES
(1, '{"CS":15, "Physics":20,"Chemistry":10}'),
(2, '{"CS":6, "Physics":8,"Chemistry":5}');
我需要select以上格式的数据。即键名(键名是动态的)作为列名和值作为数据。
id| CS | Physics | Chemistry
1 | 15 | 20 | 10
2 | 6 | 8 | 5
我使用 JSON_TABLE
从高级 SO 成员“Akina”那里得到了以下解决方案。但是这个功能只支持MySQL 8.0
MySQL 5.7 中是否有 JSON_TABLE
功能的替代方案。或者获得任何线索以获得所需的结果。
是的,老式的方式,使用 json_extract 和路径:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=403c4a6fa81b514214d3f10ddb4cf50e
SELECT t.id,
t.jdoc->'$.CS' as CS,
t.jdoc->'$.Physics' as Physics,
t.jdoc->'$.Chemistry' as Chemistry
FROM test_table t
其中 -> 是 json_extract 的 shorthand 运算符。根据您要输出的数据格式,您可能需要使用 ->> 这是 shorthand 运算符 json_unquote(json_extract()).
您可以通过构建动态路径来支持未知键,但它变得不那么可读了:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=bb9bf699ace41e6dd0e475e60b60605b
SELECT t.id,
json_extract(t.jdoc, concat('$.', json_extract(json_keys(t.jdoc), '$[0]'))) as k0,
json_extract(t.jdoc, concat('$.', json_extract(json_keys(t.jdoc), '$[1]'))) as k1,
json_extract(t.jdoc, concat('$.', json_extract(json_keys(t.jdoc), '$[2]'))) as k2
FROM test_table t;
您可以看到输出是相同的,除了列名。如果列名很重要,您可以使用准备好的语句动态生成带有字段名的查询,然后从中准备语句并执行它。看到这个 fiddle:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=fb2ab27407789bdfad04e0a53d9a0257
SELECT json_keys(t.jdoc) INTO @keys FROM test_table t LIMIT 1;
SET @query = CONCAT("SELECT t.id, "
"t.jdoc->'$.", json_extract(@keys, '$[0]'), "' as ", json_extract(@keys, '$[0]'), ", ",
"t.jdoc->'$.", json_extract(@keys, '$[1]'), "' as ", json_extract(@keys, '$[1]'), ", ",
"t.jdoc->'$.", json_extract(@keys, '$[2]'), "' as ", json_extract(@keys, '$[2]'),
"FROM test_table t;");
PREPARE stmt FROM @query;
EXECUTE stmt;
可读性直接超越 window,维护将是一件真正的苦差事。我相信变量已被弃用,所以不知道它能工作多长时间,通常建议避免 运行 动态生成 sql。但它会产生预期的结果。
请记住,执行动态生成的 sql 会使您面临许多可能的危害。您实际上是从其他地方获取文本,然后在您的系统上执行它。
我有以下 JSON 数据格式,其中包含简单的 Key/Value 对数据。
CREATE TABLE test_table (id INT, jdoc JSON);
INSERT INTO test_table VALUES
(1, '{"CS":15, "Physics":20,"Chemistry":10}'),
(2, '{"CS":6, "Physics":8,"Chemistry":5}');
我需要select以上格式的数据。即键名(键名是动态的)作为列名和值作为数据。
id| CS | Physics | Chemistry
1 | 15 | 20 | 10
2 | 6 | 8 | 5
我使用 JSON_TABLE
从高级 SO 成员“Akina”那里得到了以下解决方案。但是这个功能只支持MySQL 8.0
MySQL 5.7 中是否有 JSON_TABLE
功能的替代方案。或者获得任何线索以获得所需的结果。
是的,老式的方式,使用 json_extract 和路径:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=403c4a6fa81b514214d3f10ddb4cf50e
SELECT t.id,
t.jdoc->'$.CS' as CS,
t.jdoc->'$.Physics' as Physics,
t.jdoc->'$.Chemistry' as Chemistry
FROM test_table t
其中 -> 是 json_extract 的 shorthand 运算符。根据您要输出的数据格式,您可能需要使用 ->> 这是 shorthand 运算符 json_unquote(json_extract()).
您可以通过构建动态路径来支持未知键,但它变得不那么可读了:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=bb9bf699ace41e6dd0e475e60b60605b
SELECT t.id,
json_extract(t.jdoc, concat('$.', json_extract(json_keys(t.jdoc), '$[0]'))) as k0,
json_extract(t.jdoc, concat('$.', json_extract(json_keys(t.jdoc), '$[1]'))) as k1,
json_extract(t.jdoc, concat('$.', json_extract(json_keys(t.jdoc), '$[2]'))) as k2
FROM test_table t;
您可以看到输出是相同的,除了列名。如果列名很重要,您可以使用准备好的语句动态生成带有字段名的查询,然后从中准备语句并执行它。看到这个 fiddle:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=fb2ab27407789bdfad04e0a53d9a0257
SELECT json_keys(t.jdoc) INTO @keys FROM test_table t LIMIT 1;
SET @query = CONCAT("SELECT t.id, "
"t.jdoc->'$.", json_extract(@keys, '$[0]'), "' as ", json_extract(@keys, '$[0]'), ", ",
"t.jdoc->'$.", json_extract(@keys, '$[1]'), "' as ", json_extract(@keys, '$[1]'), ", ",
"t.jdoc->'$.", json_extract(@keys, '$[2]'), "' as ", json_extract(@keys, '$[2]'),
"FROM test_table t;");
PREPARE stmt FROM @query;
EXECUTE stmt;
可读性直接超越 window,维护将是一件真正的苦差事。我相信变量已被弃用,所以不知道它能工作多长时间,通常建议避免 运行 动态生成 sql。但它会产生预期的结果。
请记住,执行动态生成的 sql 会使您面临许多可能的危害。您实际上是从其他地方获取文本,然后在您的系统上执行它。