很多時候,我們需要在sql里面直接解析json字符串。這里針對mysql5.7版本的分水嶺進行區分。
1.對於mysql5.7以上版本
使用mysql的內置函數JSON_EXTRACT(column, '$.key'),這個函數有兩個參數,第一個參數column代表json列的列名;第二個參數key代表json字符串中的某一個key。
SELECT JSON_EXTRACT('{"priceTag":"員工/合作關鍵人","priceDiscount":"90"}', '$.priceDiscount') AS '定價折扣';
對於簡單的json字符串肯定是可以解析成功,但是對於嵌套數組的沒試過。
2.對於mysql5.7以下版本
只能充分發揮已有函數的功能去截取實現,無論實現方式是存儲過程還是簡單的sql語句,其原理都是一樣的。
第一步,將所有的花括號的閉括號'}'替換成英文逗號',';第二步,獲取key的坐標keyIndex和長度keyLength;第三步,獲取以key為起點,第一個英文逗號','的坐標symbolIndex;第四步,使用substring截取字符串SUBSTRING(targetJsonStr, keyIndex + keyLength, symbolIndex - keyIndex - keyLength);第五步,使用replace將雙引號'"'替換成空字符串'',完工。
示例:從{"priceTag": "員工/合作關鍵人","priceDiscount": "90"}中獲取priceDiscount的值。
SELECT
REPLACE(
-- SUBSTRING(s,n,len)
-- 帶有 len 參數的格式,從字符串 s 返回一個長度同 len 字符相同的子字符串,起始於位置 n。
SUBSTRING(
REPLACE(
'{"priceTag":"員工/合作關鍵人","priceDiscount":"90"}' ,
'}' ,
','
) , -- s 將初始字段中的有括號替換成','號
-- LOCATE(substr,str)
-- 返回字符串substr在字符串str中第一次出現的位置從1開始計數 。
LOCATE(
'priceDiscount":' ,
REPLACE(
'{"priceTag":"員工/合作關鍵人","priceDiscount":"90"}' ,
'}' ,
','
)
) + CHAR_LENGTH('priceDiscount":') ,-- n 起始位置
LOCATE(
',' ,
REPLACE(
'{"priceTag":"員工/合作關鍵人","priceDiscount":"90"}' ,
'}' ,
','
) ,
LOCATE(
'priceDiscount":' ,
REPLACE(
'{"priceTag":"員工/合作關鍵人","priceDiscount":"90"}' ,
'}' ,
','
)
) + CHAR_LENGTH('priceDiscount":') -- n后的第一個','號在 s 中所在的位置
) -(
LOCATE(
'priceDiscount":' ,
REPLACE(
'{"priceTag":"員工/合作關鍵人","priceDiscount":"90"}' ,
'}' ,
','
)
) + CHAR_LENGTH('priceDiscount":')
) -- 計算出了key值對應的value值的長度
) ,
'"' ,
''
) AS '定價折扣';
文字描述:
1.先將原始字符串的右'}' 替換成 ','
2.計算出key值在步驟1中的位置,當做字段截取的起始位置
3.計算出key值右邊最近的一個','號在步驟1中的位置 - 步驟2的位置 = key值對應的value值即字段截取長度
4.截取value值兩邊的雙引號,即得出value值
參考:https://www.jianshu.com/p/513acedf436d
https://blog.csdn.net/helloxiaozhe/article/details/86571387
相關函數介紹
LOCATE函數
語法 一:
LOCATE(substr,str)
返回字符串substr在字符串str中第一次出現的位置從1開始計數 。
如:
SELECT LOCATE("a","abca")
查詢結果:

語法二:
LOCATE(substr,str,pos)
返回字符串substr從pos往后數在字符串str中第一次出現的位置從1開始計數 。
如:
SELECT LOCATE("a","abca",2)
查詢結果:

注:如果str、substr中任意一個字段為null則查詢結果為null
如果substr在str中不存在則返回0
SUBSTRING函數
MYSQL中獲取子串函數 SUBSTRING(s,n,len) 帶有 len 參數的格式,從字符串 s 返回一個長度同 len 字符相同的子字符串,起始於位置 n。
也可能對 n 使用一個負值。假若這樣,則子字符串的位置起始於字符串結尾的第 n 個字符,即倒數第 n 個字符,而不是字符串的開頭位置。
參考:http://c.biancheng.net/mysql/substring.html
CHAR_LENGTH函數
返回函數內字符串的長度
如:
CHAR_LENGTH('priceDiscount":')
查詢結果:

踩坑背景:公司使用了MongoDB數據庫存放數據,但是我所做的通用統計服務數據又存放在mysql內,所以需要MongoDB的數據往mysql導入,如果是簡單的數據倒是沒啥,但是這個json數據就有點難搞了。
比如上面的例子:他的key值是固定的,順序可能也一致。MongoDB里面的數據就不一樣了
舉幾個例子:
{"lightspot":"問題解決效率高","scotoma":"1.未查客戶逾期情況2.未核實客戶身份"}
{"scotoma":"未咨詢匯款人"}
{"lightspot":"核實客戶身份;問題處理快"}
{"scotoma":"后台操作不應說出(我看下是哪個客戶)","lightspot":"1.規范用語2.問題解決思路清晰"}
順序不一致,key值不一定全
SELECT
REPLACE(
substr(
REPLACE(ifnull(`b`.`comment`, ''),'}', ','), -- 原始字段
locate('scotoma":', REPLACE(ifnull(`b`.`comment`, ''), '}', ','))+ char_length('scotoma":'), -- 起始位置
IF(locate('scotoma":',
REPLACE(ifnull(`b`.`comment`, ''),
'}',
',')
) <> 0, -- 判定key值是否存在
locate(',',
REPLACE(ifnull(`b`.`comment`, ''), '}', ','),
locate('scotoma":', REPLACE(ifnull(`b`.`comment`, ''), '}', ','))
+ char_length('scotoma":')
) - (locate('scotoma":', REPLACE(ifnull(`b`.`comment`, ''), '}', ',')) + char_length('scotoma":')) -- 有就正常取值獲取取值長度
, 0) -- 沒有就取長度0
), -- 獲取value內容
'"',
''
)
FROM ctr_new_db.cti_quality_judgement b
注:如果要運行我的這段sql只需要將sql中的`b`.`comment`替換成我上面舉例的四個字符串中的任意一個即可
文字描述:
1.先將原始字符串的右'}' 替換成 ','
2.計算出key值在步驟1中的位置,當做字段截取的起始位置
3.判定key值在這個json中是否存在,存在則按照之前的計算邏輯獲取value值的大小,不存在則取0
4.截取value值兩邊的雙引號,即得出value值
