SQLServer高效解析JSON格式數(shù)據(jù)的實例過程
1. 背景
最近碰到個需求,源數(shù)據(jù)存在posgtreSQL中,且為JSON格式。那如果在SQLServer中則 無法直接使用,需要先解析成表格行列結(jié)構(gòu)化存儲,再復(fù)用。
樣例數(shù)據(jù)如下
‘[{“key”:“2019-01-01”,“value”:“4500.0”},{“key”:“2019-01-02”,“value”:“4500.0”},{“key”:“2019-01-03”,“value”:“4500.0”},{“key”:“2019-01-04”,“value”:“4500.0”},{“key”:“2019-01-05”,“value”:“4500.0”},{“key”:“2019-01-06”,“value”:“4500.0”},{“key”:“2019-01-07”,“value”:“4500.0”},{“key”:“2019-01-08”,“value”:“4500.0”},{“key”:“2019-01-09”,“value”:“4500.0”},{“key”:“2019-01-10”,“value”:“4500.0”},{“key”:“2019-01-11”,“value”:“4500.0”},{“key”:“2019-01-12”,“value”:“4500.0”},{“key”:“2019-01-13”,“value”:“4500.0”},{“key”:“2019-01-14”,“value”:“4500.0”},{“key”:“2019-01-15”,“value”:“4500.0”},{“key”:“2019-01-16”,“value”:“4500.0”},{“key”:“2019-01-17”,“value”:“4500.0”},{“key”:“2019-01-18”,“value”:“4500.0”},{“key”:“2019-01-19”,“value”:“4500.0”},{“key”:“2019-01-20”,“value”:“4500.0”},{“key”:“2019-01-21”,“value”:“4500.0”},{“key”:“2019-01-22”,“value”:“4500.0”},{“key”:“2019-01-23”,“value”:“4500.0”},{“key”:“2019-01-24”,“value”:“4500.0”},{“key”:“2019-01-25”,“value”:“4500.0”},{“key”:“2019-01-26”,“value”:“4500.0”},{“key”:“2019-01-27”,“value”:“4500.0”},{“key”:“2019-01-28”,“value”:“4500.0”},{“key”:“2019-01-29”,“value”:“4500.0”},{“key”:“2019-01-30”,“value”:“4500.0”},{“key”:“2019-01-31”,“value”:“4500.0”}]’
研究了下方法,可以先將 JSON串 拆成獨立的 key-value對,再來對key-value子串做截取,獲取兩列數(shù)據(jù)值。
2. 拆串-拆分JSON串至key-value子串
這里主要利用行號和分隔符來組合完成拆分的功能。
參考如下樣例。
主要利用連續(xù)數(shù)值作為索引(起始值為1),從源字符串每個位置截取長度為1(分隔符的長度)的字符,如果為分隔符,則為有效的、待處理的記錄。有點類似于生物DNA檢測中的鳥槍法,先廣撒網(wǎng),再根據(jù)標記識別、追蹤。
/* * Date : 2020-07-01 * Author : 飛虹 * Sample : 拆分 指定分割符的字符串為單列多值 * Input : 字符串'jun,cong,haha' * Output : 列,值為 'jun', 'cong', 'haha' */ declare @s nvarchar(500) = 'jun,cong,haha' ,@sep nvarchar(5) = ','; with cte_Num as ( select 1 as n union all select n+1 n from cte_Num where n<100 ) select d.s, a.n ,n-len(replace(left(s, n), @sep, '')) + 1 as pos, CHARINDEX(@sep, s+@sep, n), substring(s, n, CHARINDEX(@sep, s+@sep, n)-n) as element from (select @s as s) as d join cte_Num a on n<=len(s) and substring(@sep+s, n, 1) = @sep
3. 取值-創(chuàng)建函數(shù)截取key-value串的值
基于第2步的結(jié)果,可以將JSON長串拆分為 key-value字符串,如 “2020-01-01”:“98.99”。到這一步,就好辦了。既可以自己寫表值函數(shù)來返回結(jié)果,也可以直接通過substring來截取。這里開發(fā)一個表值函數(shù),來進行封裝。
/* ******************************************************************************* * Date : 2020-07-01 * Author : 飛虹 * Note : 利用patindex正則匹配字符,在while中對字符進行逐個匹配、替換為空。 * Function : getDateAmt * Input : key-value字符串,如 "2020-01-01":"98.99" * Output : Table類型(日期列,數(shù)值列)。值為 2020-01-01, 98.99 ******************************************************************************* */ CREATE FUNCTION dbo.getDateAmt(@S VARCHAR(100)) RETURNS @tb_rs table(dt date, amt decimal(28,14)) AS BEGIN WHILE PATINDEX('%[^0-9,-.]%',@S) > 0 BEGIN -- 匹配:去除非數(shù)字 、頓號、橫線 的字符 set @s=stuff(@s,patindex('%[^0-9,-.]%',@s),1,'') END insert into @tb_rs select SUBSTRING(@s,1,charindex(',',@s)-1) , substring(@s,charindex(',',@s)+1, len(@s) ) return END GO --測試 select * from DBO.getDateAmt('{"key":"2019-01-01","value":"4500.0"')
4. 完整樣例
附上完整腳本樣例,全程CTE,直接查詢,預(yù)覽效果。
;with cte_t1 as ( select * from ( values('jun','[{"key":"2019-01-01","value":"4500.0"},{"key":"2019-01-02","value":"4500.0"},{"key":"2019-01-03","value":"4500.0"},{"key":"2019-01-04","value":"4500.0"},{"key":"2019-01-05","value":"4500.0"},{"key":"2019-01-06","value":"4500.0"},{"key":"2019-01-07","value":"4500.0"},{"key":"2019-01-08","value":"4500.0"},{"key":"2019-01-09","value":"4500.0"},{"key":"2019-01-10","value":"4500.0"},{"key":"2019-01-11","value":"4500.0"},{"key":"2019-01-12","value":"4500.0"},{"key":"2019-01-13","value":"4500.0"},{"key":"2019-01-14","value":"4500.0"},{"key":"2019-01-15","value":"4500.0"},{"key":"2019-01-16","value":"4500.0"},{"key":"2019-01-17","value":"4500.0"},{"key":"2019-01-18","value":"4500.0"},{"key":"2019-01-19","value":"4500.0"},{"key":"2019-01-20","value":"4500.0"},{"key":"2019-01-21","value":"4500.0"},{"key":"2019-01-22","value":"4500.0"},{"key":"2019-01-23","value":"4500.0"},{"key":"2019-01-24","value":"4500.0"},{"key":"2019-01-25","value":"4500.0"},{"key":"2019-01-26","value":"4500.0"},{"key":"2019-01-27","value":"4500.0"},{"key":"2019-01-28","value":"4500.0"},{"key":"2019-01-29","value":"4500.0"},{"key":"2019-01-30","value":"4500.0"},{"key":"2019-01-31","value":"4500.0"}]') ,('congc','[{"key":"2019-01-01","value":"347.82608695652175"},{"key":"2019-01-02","value":"347.82608695652175"},{"key":"2019-01-03","value":"347.82608695652175"},{"key":"2019-01-04","value":"347.82608695652175"},{"key":"2019-01-07","value":"347.82608695652175"},{"key":"2019-01-08","value":"347.82608695652175"},{"key":"2019-01-09","value":"347.82608695652175"},{"key":"2019-01-10","value":"347.82608695652175"},{"key":"2019-01-11","value":"347.82608695652175"},{"key":"2019-01-14","value":"347.82608695652175"},{"key":"2019-01-15","value":"347.82608695652175"},{"key":"2019-01-16","value":"347.82608695652175"},{"key":"2019-01-17","value":"347.82608695652175"},{"key":"2019-01-18","value":"347.82608695652175"},{"key":"2019-01-21","value":"347.82608695652175"},{"key":"2019-01-22","value":"347.82608695652175"},{"key":"2019-01-23","value":"347.82608695652175"},{"key":"2019-01-24","value":"347.82608695652175"},{"key":"2019-01-25","value":"347.82608695652175"},{"key":"2019-01-28","value":"347.82608695652175"},{"key":"2019-01-29","value":"347.82608695652175"},{"key":"2019-01-30","value":"347.82608695652175"},{"key":"2019-01-31","value":"347.82608695652175"}]') ) as t(name, jsonStr) ) , cte_rn as ( select 1 as rn union all select rn+1 from cte_rn where rn < 1000 ) , cte_splitJson as ( SELECT a.name ,replace(replace(a.jsonStr,'[',''),']','') as jsonStr ,substring(replace(replace(a.jsonStr,'[',''),']','') , b1.rn , charindex('},', replace(replace(a.jsonStr,'[',''),']','')+'},', b1.rn)-b1.rn ) as value_json from cte_t1 a cross join cte_rn b1 where substring('},'+replace(replace(a.jsonStr,'[',''),']',''), rn, 2) = '},' ) select * from cte_splitJson a cross apply dbo.getDateAmt(a.value_json) as t1 -- 注意這里生成行號時, 需要設(shè)置默認遞歸次數(shù) option(maxrecursion 0)
5. 問題
經(jīng)過在個人普通配置PC實測,性能有點堪憂,耗時:數(shù)據(jù)量 約為15mins:50W ,不太能接受。有興趣或者經(jīng)歷過的伙伴,出手來協(xié)助, 怎么提高效率,或者來個新方案?
到此這篇關(guān)于SQLServer高效解析JSON格式數(shù)據(jù)的文章就介紹到這了,更多相關(guān)SQLServer解析JSON數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SQLServer查詢歷史執(zhí)行記錄的方法實現(xiàn)
有的時候,需要知道近段時間SQLSERVER執(zhí)行了什么語句,本文主要介紹了SQLServer查詢歷史執(zhí)行記錄的方法實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2023-09-09SqlServer參數(shù)化查詢之where in和like實現(xiàn)之xml和DataTable傳參介紹
在上一篇Sql Server參數(shù)化查詢之where in和like實現(xiàn)詳解中介紹了在Sql Server使用參數(shù)化查詢where in的幾種實現(xiàn)方案,遺漏了xml和表值參數(shù),這里做一個補充2012-05-05存儲過程配合UpdateDaset方法批量插入Dataset數(shù)據(jù)實現(xiàn)代碼
用存儲過程配合UpdateDaset方法批量插入Dataset數(shù)據(jù),感興趣的你可不要錯過了哈,希望本文提供知識點可以幫助到你2013-02-02sqlserver 數(shù)據(jù)庫學(xué)習(xí)筆記
sqlserver 數(shù)據(jù)庫學(xué)習(xí)筆記,學(xué)習(xí)sqlserver的朋友可以參考下。2011-11-11