如果包含 json 文档作为字符串,如何从 MySQL(5.6) 列中获取值
Posted
技术标签:
【中文标题】如果包含 json 文档作为字符串,如何从 MySQL(5.6) 列中获取值【英文标题】:How to get values from MySQL(5.6) column if that contains json document as string 【发布时间】:2016-10-15 10:29:40 【问题描述】:如果包含 JSON 文档作为字符串,如何从 mysql(5.6) 列获取值
例如,如果我们有一个表 - 雇员,我们有三列 身份证、姓名和学历。 并且列 educations 包含 JSON 文档形式的数据
"ug":"bsc","pg":"mca","ssc":"10th"
我需要来自educations 列的ug 和pg 的值
我们可以使用 MySQL(5.6) 查询来做到这一点吗?
【问题讨论】:
MySQL 对 JSON 数据一无所知。对它来说,它只是一团数据。您需要在从数据库中检索 JSON 之后对其进行解码(使用您用来访问数据库的任何语言)。 好像 MySQL 5.7 增加了 JSON 支持:dev.mysql.com/doc/refman/5.7/en/json.html#json-paths 【参考方案1】:为了能够做你想做的事,你需要 MySQL 5.7.8+。从 5.7.8 开始,您可以使用 JSON_EXTRACT
函数从 JSON 字符串中提取值:
SELECT JSON_EXTRACT('"id": 14, "name": "Aztalan"', '$.name');
+---------------------------------------------------------+
| JSON_EXTRACT('"id": 14, "name": "Aztalan"', '$.name') |
+---------------------------------------------------------+
| "Aztalan" |
+---------------------------------------------------------+
取自here。
在 MySQL 5.6 中,您无法获得所需的值,因为 MySQL 不知道 JSON 对象是什么。所以你的选择是:
升级到 5.7.8+ 用处理 JSON 的东西解析查询结果: 可以是 php json_decode(或您的语言中的等效项) 像http://json.parser.online.fr/这样的在线工具【讨论】:
【参考方案2】:在 MySQL 5.6 中,JSON_EXTRACT
默认不可用。
如果在 MySQL 5.6 中仍然需要访问 json 数据,则需要编写自定义函数。
DELIMITER $$
DROP FUNCTION IF EXISTS `json_extract_c`$$
CREATE DEFINER=`root`@`%` FUNCTION `json_extract_c`(
details TEXT,
required_field VARCHAR (255)
) RETURNS TEXT CHARSET latin1
BEGIN
RETURN TRIM(
BOTH '"' FROM SUBSTRING_INDEX(
SUBSTRING_INDEX(
SUBSTRING_INDEX(
details,
CONCAT(
'"',
SUBSTRING_INDEX(required_field,'$.', - 1),
'"'
),
- 1
),
'",',
1
),
':',
- 1
)
) ;
END$$
DELIMITER ;
这会有所帮助。我已经创建并测试了。
【讨论】:
返回值末尾包含“”加给定: "distance":55.62,"totalDistance":11946.83 JSON_EXTRACT_C(attributes, "$.distance") 给出11946.83 检查您的数据,我正在使用此功能作为过去几个月的替代品,根本没有任何问题。 你能用我的数据进行测试吗? 这不是特别健壮或正确的。select json_extract_c('"a": 1, "b": 2', "$.a");
-> 2
, select json_extract_c('"a": "1"', "$.a")
-> "1
, select json_extract_c('"a": "a"', "$.a")
-> 空字符串。其他提供手卷功能的答案也是基于这个,所以??♂️
@gaborsch 的答案解决了上述所有示例,应检查为正确答案【参考方案3】:
当 JSON 文本中未提及该元素时,之前的两个答案都对我不起作用。还有我改进的功能:
DELIMITER $$
DROP FUNCTION IF EXISTS `json_extract_c`$$
CREATE FUNCTION `json_extract_c`(
details TEXT,
required_field VARCHAR (255)
) RETURNS TEXT CHARSET latin1
BEGIN
DECLARE search_term TEXT;
SET details = SUBSTRING_INDEX(details, "", -1);
SET details = SUBSTRING_INDEX(details, "", 1);
SET search_term = CONCAT('"', SUBSTRING_INDEX(required_field,'$.', - 1), '"');
IF INSTR(details, search_term) > 0 THEN
RETURN TRIM(
BOTH '"' FROM SUBSTRING_INDEX(
SUBSTRING_INDEX(
SUBSTRING_INDEX(
details,
search_term,
- 1
),
',"',
1
),
':',
-1
)
);
ELSE
RETURN NULL;
END IF;
END$$
DELIMITER ;
【讨论】:
上述方法不起作用:选择 json_extract_c('"foo":"fing", "bar":"bing"',"$.foo") 应该返回 "bing"返回“fing” 我提供的函数在昏迷后不查看空格。它适用于 '"foo":"fing","bar":"bing"',但不适用于 '"foo":"fing", "bar":"bing"'。查看@gnought 答案以获得更高级的实现。【参考方案4】:这是我用于 JSON 提取的 3 个 SQL 存储函数。它们处理嵌套对象,但只关心键名。键必须是字符串,值可以是字符串、数字或布尔值。数组没有得到很好的处理,只选择了第一个值。如果没有找到值,它们会返回 NULL
。
第一个,json_extract_1
如果有多个具有相同名称的键,则仅选择第一个值。如果您离开 LIMIT 1
子句,如果找到更多键(安全模式),它会抛出“子查询返回超过 1 行”。
第二个,json_extract_m
将所有具有相同键的值收集到一个逗号分隔的列表中。
第三个,json_extract_c
是最慢的,但它也正确地处理带有逗号的值。在绝对必要时使用它,例如文字描述。
这三个限制是 999 个键。如果为numbers
子选择准备一个表,则可以加快速度。
DELIMITER $$
/*
* Single-value JSON extract - picks the first value
*/
DROP FUNCTION IF EXISTS `json_extract_1`$$
CREATE FUNCTION `json_extract_1`(json_txt TEXT, search_key VARCHAR (255))
RETURNS TEXT
BEGIN
RETURN (SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(txt,':',-1), '"', 2), '"', -1)) AS val
FROM (
SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX( SUBSTRING_INDEX(json_txt , ',', n), ',', -1 ), '', 1), '', -1)) AS txt
FROM (SELECT t1.v + t2.v*10 + t3.v*100 AS n
FROM (SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t1,
(SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t2,
(SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t3) numbers
WHERE CHAR_LENGTH(json_txt ) - CHAR_LENGTH(REPLACE(json_txt , ',', '')) >= n - 1
AND n>0 ) sp
WHERE TRIM(SUBSTRING_INDEX(txt,':',1)) = CONCAT('"',search_key,'"')
LIMIT 1 -- comment out for safe mode
);
END$$
/*
* Multi-value JSON extract - collects all values, group_concats them with comma
*/
DROP FUNCTION IF EXISTS `json_extract_m`$$
CREATE FUNCTION `json_extract_m`(json_txt TEXT, search_key VARCHAR (255))
RETURNS TEXT
BEGIN
RETURN (SELECT GROUP_CONCAT(TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(txt,':',-1), '"', 2), '"', -1))) AS val
FROM (
SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX( SUBSTRING_INDEX(json_txt , ',', n), ',', -1 ), '', 1), '', -1)) AS txt
FROM (SELECT t1.v + t2.v*10 + t3.v*100 AS n
FROM (SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t1,
(SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t2,
(SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t3) numbers
WHERE CHAR_LENGTH(json_txt ) - CHAR_LENGTH(REPLACE(json_txt , ',', '')) >= n - 1
AND n>0 ) sp
WHERE TRIM(SUBSTRING_INDEX(txt,':',1)) = CONCAT('"',search_key,'"'));
END$$
/*
* Comma-safe JSON extract - treats values with commas correctly, but slow like hell
*/
DROP FUNCTION IF EXISTS `json_extract_c`$$
CREATE FUNCTION `json_extract_c`(json_txt TEXT, search_key VARCHAR (255))
RETURNS TEXT
BEGIN
DROP TEMPORARY TABLE IF EXISTS json_parts;
DROP TEMPORARY TABLE IF EXISTS json_parts2;
DROP TEMPORARY TABLE IF EXISTS json_indexes;
CREATE TEMPORARY TABLE json_parts AS
SELECT n, IF(INSTR(txt,':')>0 AND (INSTR(txt,',')+INSTR(txt,'')>0),1,0) AS this_val, IF(INSTR(txt,':')>0 AND (INSTR(txt,',')+INSTR(txt,'')=0),1,0) AS next_val, IF(INSTR(txt,',')+INSTR(txt,'')>0,1,0) AS next_key, txt
FROM (SELECT n, IF(n%2,txt,REPLACE(txt,',','|')) AS txt
FROM (SELECT n, TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(json_txt , '"', n), '"', -1 )) AS txt
FROM (SELECT t1.v + t2.v*10 + t3.v*100 AS n
FROM (SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t1,
(SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t2,
(SELECT 0 AS v UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t3) numbers
WHERE CHAR_LENGTH(json_txt ) - CHAR_LENGTH(REPLACE(json_txt , '"', '')) >= n - 1
AND n>0) v
) v2;
CREATE TEMPORARY TABLE json_parts2 AS SELECT * FROM json_parts;
CREATE TEMPORARY TABLE json_indexes AS
SELECT p1.n, p1.n+1 AS key_idx, MIN(GREATEST(IF(p2.this_val,p2.n,0), IF(p2.next_val,p2.n+1,0))) AS val_idx, p2.this_val AS trim_val
FROM json_parts p1
JOIN json_parts2 p2 ON (p1.n < p2.n AND (p2.this_val OR p2.next_val))
WHERE p1.next_key
GROUP BY p1.n;
RETURN (SELECT json_values.v
FROM (SELECT p1.txt AS k, REPLACE(IF(i.trim_val, regexp_replace(regexp_replace(p2.txt,'^[: ]+',''),'[, ]+$',''), p2.txt), '|', ',') AS v
FROM json_indexes i
JOIN json_parts p1 ON (i.key_idx = p1.n)
JOIN json_parts2 p2 ON (i.val_idx = p2.n)) json_values
WHERE json_values.k = search_key);
END$$
DELIMITER ;
是的,如果有机会,请尝试升级到 MySQL 5.7,内置函数的工作效率更高。
【讨论】:
最好的解决方案,实际上是迄今为止唯一没有问题的解决方案,感谢@gaborsch【参考方案5】:Rahul 的回答对我来说不是很好,所以我编辑了它,这对我有用:
DELIMITER $$
DROP FUNCTION IF EXISTS `json_extract_c`$$
CREATE FUNCTION `json_extract_c`(
details TEXT,
required_field VARCHAR (255)
) RETURNS TEXT CHARSET latin1
BEGIN
SET details = TRIM(LEADING '' FROM TRIM(details));
SET details = TRIM(TRAILING '' FROM TRIM(details));
RETURN TRIM(
BOTH '"' FROM SUBSTRING_INDEX(
SUBSTRING_INDEX(
SUBSTRING_INDEX(
details,
CONCAT(
'"',
SUBSTRING_INDEX(required_field,'$.', - 1),
'":'
),
- 1
),
',"',
1
),
':',
-1
)
) ;
END$$
DELIMITER ;
【讨论】:
【参考方案6】:如果您在表格字段中嵌套了 JSON,上述功能将无法正常工作。
因为我需要 mysql 5.6 上的 JSON_EXTRACT,所以我自己编写了一个原始函数的副本,可以像 mysql 5.7 中的本机函数一样提取值
用法:
SELECT JSON_EXTRACT_NESTED(table_field,"json_level1.json_level2.json_level3") FROM table;
如果您有一级 JSON,则使用:
SELECT JSON_EXTRACT_NESTED(table_field,"json_level1") FROM table;
在数据库中你必须添加两个函数:
主要功能:
CREATE FUNCTION `json_extract_nested`(
_field TEXT,
_variable TEXT
) RETURNS TEXT CHARSET latin1
BEGIN
DECLARE X INT DEFAULT 0;
DECLARE fieldval1 TEXT;
DECLARE arrayName,arrayValue TEXT;
SET arrayName = SUBSTRING_INDEX(_variable, '.', 1);
IF(LOCATE('%',arrayName)> 0) THEN
SET _field = SUBSTRING_INDEX(_field, "", -1);
SET _field = SUBSTRING_INDEX(_field, "", 1);
RETURN TRIM(
BOTH '"' FROM SUBSTRING_INDEX(
SUBSTRING_INDEX(
SUBSTRING_INDEX(
_field,
CONCAT(
'"',
SUBSTRING_INDEX(_variable,'$.', - 1),
'":'
),
- 1
),
',"',
1
),
':',
-1
)
) ;
ELSE
SET arrayValue = json_array_value(_field, arrayName);
WHILE X < (LENGTH(_variable) - LENGTH(REPLACE(_variable, '.', ""))) DO
IF(LENGTH(_variable) - LENGTH(REPLACE(_variable, '.', ""))>X) THEN
SET arrayName = SUBSTRING_INDEX(SUBSTRING_INDEX(_variable, '.', X+2),'.',-1);
END IF;
IF(arrayName<>'') THEN
SET arrayValue = json_array_value(arrayValue, arrayName);
END IF;
SET X = X + 1;
END WHILE;
END IF;
RETURN arrayValue;
END$$
DELIMITER ;
辅助功能(主功能需要):
CREATE FUNCTION `json_array_value`(
_field TEXT,
arrayName VARCHAR (255)
) RETURNS TEXT CHARSET latin1
BEGIN
DECLARE arrayValue, arrayValueTillDelimit TEXT;
DECLARE arrayStartDelimiter, arrayEndDelimiter VARCHAR(10);
DECLARE arrayCountDelimiter INT;
DECLARE countBracketLeft, countBracketRight INT DEFAULT 0;
DECLARE X INT DEFAULT 0;
DECLARE arrayNameQuoted VARCHAR(255);
SET arrayNameQuoted = CONCAT('"',arrayName,'"');
/*check arrayname exist*/
IF(LOCATE(arrayNameQuoted,_field)= 0) THEN
RETURN NULL;
ELSE
/*get value behind arrayName1*/
SET _field = SUBSTRING(_field,1,LENGTH(_field)-1);
SET arrayValue = SUBSTRING(_field, LOCATE(arrayNameQuoted,_field)+LENGTH(arrayNameQuoted)+1, LENGTH(_field));
/*get json delimiter*/
SET arrayStartDelimiter = LEFT(arrayValue, 1);
IF(arrayStartDelimiter='') THEN
SET arrayEndDelimiter = '';
loopBrackets: WHILE X < (LENGTH(arrayValue)) DO
SET countBracketLeft = countBracketLeft +IF(SUBSTRING(arrayValue,X,1)=arrayStartDelimiter,1,0);
SET countBracketRight = countBracketRight +IF(SUBSTRING(arrayValue,X,1)=arrayEndDelimiter,1,0);
IF(countBracketLeft<>0 AND countBracketLeft=countBracketRight) THEN
SET arrayCountDelimiter = X;
LEAVE loopBrackets;
ELSE
SET X = X + 1;
END IF;
END WHILE;
ELSEIF(arrayStartDelimiter='[') THEN
SET arrayEndDelimiter = ']';
SET arrayCountDelimiter = LENGTH(SUBSTRING_INDEX(arrayValue, arrayEndDelimiter, 0));
ELSEIF(arrayStartDelimiter='"') THEN
SET arrayEndDelimiter = '"';
SET arrayCountDelimiter = LENGTH(SUBSTRING_INDEX(arrayValue, arrayEndDelimiter, 0));
ELSE
SET arrayStartDelimiter = "";
IF((LOCATE(",",arrayValue)> LOCATE("",arrayValue))) THEN
SET arrayEndDelimiter = ",";
ELSE
SET arrayEndDelimiter = "";
END IF;
SET arrayCountDelimiter = LENGTH(SUBSTRING_INDEX(arrayValue, arrayEndDelimiter, 0));
END IF;
SET arrayValueTillDelimit = SUBSTRING(arrayValue, 1, arrayCountDelimiter);
SET arrayCountDelimiter = LENGTH(arrayValueTillDelimit) - LENGTH(REPLACE(arrayValueTillDelimit, arrayStartDelimiter, ""));
SET arrayValue = SUBSTR(arrayValue,LENGTH(arrayStartDelimiter)+1);
IF(arrayStartDelimiter='') THEN
SET arrayValue = SUBSTRING_INDEX(arrayValue, arrayEndDelimiter, arrayCountDelimiter);
ELSE
SET arrayValue = SUBSTRING_INDEX(arrayValue, arrayEndDelimiter, arrayCountDelimiter+1);
END IF;
RETURN (arrayValue);
END IF;
END$$
DELIMITER ;
【讨论】:
如果有人打算让他的服务器崩溃,可以试试。执行时间:6 秒 577 毫秒【参考方案7】:这是我们在 MySQL 5.6 中部署的json_extract_c
已测试:
select json_extract_c('"a": 1, "b": 2', "$.a"); -> 1;
select json_extract_c('"a": "1", "b": "2"', "$.a"); -> 1;
select json_extract_c('"a":"1","b":"2"', "$.a"); -> 1;
select json_extract_c('"a" :"1", "b" :"2"', "$.a"); -> 1;
select json_extract_c('"b" :"a", "a" :"2"', "$.a"); -> 2;
select json_extract_c('"a" : "a", "a" :"2"', "$.a"); -> a;
select json_extract_c('"a": "1"', "$.a"); -> 1
select json_extract_c('"a": "a"', "$.a"); -> a
select json_extract_c('"a" : "a"', "$.a"); -> a
select json_extract_c('"a.a" : "a"', "$.a"); -> NULL
select json_extract_c('"a\"a" : "9"', "$.a"); -> NULL
不支持:
-
嵌套 json
json 值中的转义双引号,例如
select json_extract_c('"a\"a" : "9", "a" : "a\"a"', "$.a");
-> 一个
限制:
-
如果有多个相同的字段,只会提取第一个字段,
e.g. select json_extract_c('"a" : 1, "a" : "2', "$.a");
-> 1
DELIMITER $$
DROP function if exists json_extract_c$$
CREATE FUNCTION json_extract_c(
details TEXT,
required_field VARCHAR (255)
) RETURNS TEXT CHARSET utf8mb4
DETERMINISTIC
NO SQL
BEGIN
DECLARE search_term, val TEXT;
DECLARE pos INT signed DEFAULT 1;
-- Remove '' and ''
SET details = SUBSTRING_INDEX(details, "", -1);
SET details = SUBSTRING_INDEX(details, "", 1);
-- Transform '$.xx' to be '"xx"'
SET search_term = CONCAT('"', SUBSTRING_INDEX(required_field,'$.', - 1), '"');
searching: LOOP
SET pos = LOCATE(search_term, details);
-- Keep searching if the field contains escape chars
WHILE pos > 0 AND RIGHT(LEFT(details, pos-1), 1) = '\\'
DO
SET details = SUBSTR(details, pos+LENGTH(search_term));
SET pos = LOCATE(search_term, details);
END WHILE;
-- Return NULL if not found
IF pos <= 0 THEN
RETURN NULL;
END IF;
SET pos = LENGTH(search_term)+pos;
SET details = SUBSTR(details, pos);
SET val = TRIM(details);
-- see if we reach the value that is a leading colon ':'
IF LEFT(val, 1) = ':' THEN
RETURN TRIM(
TRAILING ',' FROM
TRIM(
SUBSTRING_INDEX(
TRIM(
BOTH '"' FROM TRIM(
SUBSTR(
val
, 2
)
)
)
, '"', 1
)
)
);
ELSE
ITERATE searching;
END IF;
END LOOP;
END$$
DELIMITER ;
【讨论】:
这适用于几行。如果是多行,则需要更长的时间并且查询不会完成【参考方案8】:为那些可能无法直观地看到 SQL 函数中的字符串操作的人(如我)提供此处给出的答案的替代视图。此版本将允许您明确查看文本解析的每个步骤。这适用于 MySQL 5.6,当然可以组合在一起而不使用任何变量。
DELIMITER $$
DROP FUNCTION IF EXISTS `json_extract_c`$$
CREATE FUNCTION `json_extract_c`(
details TEXT,
required_field VARCHAR (255)
) RETURNS TEXT CHARSET latin1
BEGIN
/* get key from function passed required field value */
set @JSON_key = SUBSTRING_INDEX(required_field,'$.', -1);
/* get everything to the right of the 'key = <required_field>' */
set @JSON_entry = SUBSTRING_INDEX(details,CONCAT('"', @JSON_key, '"'), -1 );
/* get everything to the left of the trailing comma */
set @JSON_entry_no_trailing_comma = SUBSTRING_INDEX(@JSON_entry, ",", 1);
/* get everything to the right of the leading colon after trimming trailing and leading whitespace */
set @JSON_entry_no_leading_colon = TRIM(LEADING ':' FROM TRIM(@JSON_entry_no_trailing_comma));
/* trim off the leading and trailing double quotes after trimming trailing and leading whitespace*/
set @JSON_extracted_entry = TRIM(BOTH '"' FROM TRIM(@JSON_entry_no_leading_colon));
RETURN @JSON_extracted_entry;
END$$
DELIMITER ;
【讨论】:
【参考方案9】:以下答案对我有用。它从值中删除双引号。
DELIMITER $$
DROP FUNCTION IF EXISTS `json_extract_values`$$
CREATE DEFINER=`root`@`localhost` FUNCTION `json_extract_values`(
details TEXT,
required_field VARCHAR (255)
) RETURNS TEXT CHARSET latin1
BEGIN
SET details = SUBSTRING_INDEX(details, "", -1);
SET details = SUBSTRING_INDEX(details, "", 1);
RETURN
SUBSTRING_INDEX(
TRIM(
TRAILING '"' FROM
SUBSTRING_INDEX(
details,
CONCAT(
'"',
SUBSTRING_INDEX(required_field,'$.', - 1),
'":'
),
-1 )
),
'"',
-1);
END$$
DELIMITER ;
【讨论】:
【参考方案10】:是的,你绝对可以在 mysql 中使用 JSON_EXTRACT() 函数。
让我们获取一个包含 JSON 的表(此处为表 client_services
):
+-----+-----------+--------------------------------------+
| id | client_id | service_values |
+-----+-----------+------------+-------------------------+
| 100 | 1000 | "quota": 1,"data_transfer":160000 |
| 101 | 1000 | "quota": 2,"data_transfer":800000 |
| 102 | 1000 | "quota": 3,"data_transfer":70000 |
| 103 | 1001 | "quota": 1,"data_transfer":97000 |
| 104 | 1001 | "quota": 2,"data_transfer":1760 |
| 105 | 1002 | "quota": 2,"data_transfer":1060 |
+-----+-----------+--------------------------------------+
要选择每个 JSON 字段,请运行以下查询:
SELECT
id, client_id,
json_extract(service_values, '$.quota') AS quota,
json_extract(service_values, '$.data_transfer') AS data_transfer
FROM client_services;
所以输出将是:
+-----+-----------+----------------------+
| id | client_id | quota | data_transfer|
+-----+-----------+----------------------+
| 100 | 1000 | 1 | 160000 |
| 101 | 1000 | 2 | 800000 |
| 102 | 1000 | 3 | 70000 |
| 103 | 1001 | 1 | 97000 |
| 104 | 1001 | 2 | 1760 |
| 105 | 1002 | 2 | 1060 |
+-----+-----------+----------------------+
希望这能解决您的问题!
【讨论】:
问题明确指出 5.6 JSON_EXTRACT() 不可用的地方。【参考方案11】:使用SUBSTRING_INDEX
函数如下:
select * from (select id, name,
substring_index(substring_index(educations, "ug\":\"", -1), "\"", 1) as ug,
substring_index (substring_index(educations, "pg\":\"", -1), "\"", 1) as pg
from employee) as t1;
让我知道它是否有效。您也可以根据上面得到的列添加条件。
【讨论】:
【参考方案12】:派对迟到了。
到目前为止,我们知道 json 支持更新版本的 mysql 和 mariaDB。 (来自 mysql 5.7+ 和 mariaDB 10.2+)
但是我们仍然可以看到一些地方使用旧的 mysql 5.6 版本。例如:一些共享托管服务提供商。
所以,这是我对JSON_EXTRACT()
的替代方法的版本。
用例:
select * From offer;
+----------+-------------------------------+-----------------------+
| offer_id | terms | name |
+----------+-------------------------------+-----------------------+
| 1 | "qty": 3, "total": 600.00 | x |
| 2 | "qty": 2, "discount": 15.00 | Buy 2 GET ONE 15% OFF |
| 3 | "discount": 9.09 | Buy 1 SAVE 10/- |
+----------+-------------------------------+-----------------------+
4 rows in set (0.001 sec)
SELECT offer_id
, terms
, json_extract_c(terms, 'qty') as offer_qty
, json_extract_c(terms, 'discount') as offer_discount
, json_extract_c(terms, 'total') as offer_total
FROM offer;
+----------+-------------------------------+-----------+----------------+-------------+
| offer_id | terms | offer_qty | offer_discount | offer_total |
+----------+-------------------------------+-----------+----------------+-------------+
| 1 | "qty": 3, "total": 600.00 | 3 | NULL | 600.00 |
| 2 | "qty": 2, "discount": 15.00 | 2 | 15.00 | NULL |
| 3 | "discount": 9.09 | NULL | 9.09 | NULL |
+----------+-------------------------------+-----------+----------------+-------------+
4 rows in set (0.003 sec)
自定义函数:
DELIMITER $$
CREATE FUNCTION `json_extract_c`(
target VARCHAR(50)
, jkey VARCHAR(50)
) RETURNS varchar(10) CHARSET utf8
BEGIN
DECLARE newtarget VARCHAR(50) DEFAULT trim(leading '' from trim(trailing '' from target));
DECLARE targa VARCHAR(50) DEFAULT '';
DECLARE thekey VARCHAR(50);
DECLARE theval VARCHAR(10);
WHILE LENGTH(newtarget) > 0 DO
SET targa = substring_index(newtarget, ',', 1);
IF LOCATE(',', newtarget) > 0 THEN
SET newtarget = substring_index(newtarget, ',', -1);
ELSE
SET newtarget = '';
END IF;
SET thekey = substring_index(targa, ':', 1);
SET thekey = TRIM(BOTH '"' FROM TRIM(thekey));
SET theval = substring_index(targa, ':', -1);
IF thekey = jkey THEN
RETURN TRIM(theval);
END IF;
END WHILE;
RETURN NULL;
END$$
【讨论】:
以上是关于如果包含 json 文档作为字符串,如何从 MySQL(5.6) 列中获取值的主要内容,如果未能解决你的问题,请参考以下文章
如何从 JsonParser (Jackson Json) 获取底层字符串