在SqlServer 中解析JSON数据 [parseJSON] 函数 数据库中 解析JSON
使用如下:
SELECT *
FROM parseJSON('{
"联系人":
{
"姓名": "huang",
"网名": "HTL",
"AGE": 05,
"男人":true,
"PhoneNumbers":
{
"mobile":"135123100514",
"phone":"0251-123456789"
} }
}
');
函数定义如下:
CREATE FUNCTION [dbo].[parseJSON] ( @JSON NVARCHAR(MAX) )
RETURNS @hierarchy TABLE
(
element_id INT IDENTITY(1, 1)
NOT NULL , /* internal surrogate primary key gives the order of parsing and the list order */
sequenceNo [INT] NULL , /* the place in the sequence for the element */
parent_ID INT ,/* if the element has a parent then it is in this column. The document is the ultimate parent, so you can get the structure from recursing from the document */
Object_ID INT ,/* each list or object has an object id. This ties all elements to a parent. Lists are treated as objects here */
NAME NVARCHAR(2000) ,/* the name of the object */
StringValue NVARCHAR(MAX) NOT NULL ,/*the string representation of the value of the element. */
ValueType VARCHAR(10) NOT NULL /* the declared type of the value represented as a string in StringValue*/ )
AS
BEGIN DECLARE @FirstObject INT , --the index of the first open bracket found in the JSON string
@OpenDelimiter INT ,--the index of the next open bracket found in the JSON string
@NextOpenDelimiter INT ,--the index of subsequent open bracket found in the JSON string
@NextCloseDelimiter INT ,--the index of subsequent close bracket found in the JSON string
@Type NVARCHAR(10) ,--whether it denotes an object or an array
@NextCloseDelimiterChar CHAR(1) ,--either a '}' or a ']'
@Contents NVARCHAR(MAX) , --the unparsed contents of the bracketed expression
@Start INT , --index of the start of the token that you are parsing
@end INT ,--index of the end of the token that you are parsing
@param INT ,--the parameter at the end of the next Object/Array token
@EndOfName INT ,--the index of the start of the parameter at end of Object/Array token
@token NVARCHAR(200) ,--either a string or object
@value NVARCHAR(MAX) , -- the value as a string
@SequenceNo INT , -- the sequence number within a list
@name NVARCHAR(200) , --the name as a string
@parent_ID INT ,--the next parent ID to allocate
@lenJSON INT ,--the current length of the JSON String
@characters NCHAR(36) ,--used to convert hex to decimal
@result BIGINT ,--the value of the hex symbol being parsed
@index SMALLINT ,--used for parsing the hex value
@Escape INT; --the index of the next escape character DECLARE @Strings TABLE /* in this temporary table we keep all strings, even the names of the elements, since they are 'escaped' in a different way, and may contain, unescaped, brackets denoting objects or lists. These are replaced in the JSON string by tokens representing the string */
(
String_ID INT IDENTITY(1, 1) ,
StringValue NVARCHAR(MAX)
); SELECT--initialise the characters to convert hex to ascii
@characters = '0123456789abcdefghijklmnopqrstuvwxyz' ,
@SequenceNo = 0 , --set the sequence no. to something sensible. /* firstly we process all strings. This is done because [{} and ] aren't escaped in strings, which complicates an iterative parse. */
@parent_ID = 0; WHILE 1 = 1 --forever until there is nothing more to do
BEGIN SELECT @Start = PATINDEX('%[^a-zA-Z]["]%',
@JSON COLLATE SQL_Latin1_General_CP850_BIN);--next delimited string IF @Start = 0
BREAK; --no more so drop through the WHILE loop IF SUBSTRING(@JSON, @Start + 1, 1) = '"'
BEGIN --Delimited Name SET @Start = @Start + 1; SET @end = PATINDEX('%[^\]["]%',
RIGHT(@JSON,
LEN(@JSON + '|') - @Start)); END; IF @end = 0 --no end delimiter to last string
BREAK; --no more SELECT @token = SUBSTRING(@JSON, @Start + 1, @end - 1); --now put in the escaped control characters SELECT @token = REPLACE(@token, FromString, ToString)
FROM ( SELECT '\"' AS FromString ,
'"' AS ToString
UNION ALL
SELECT '\\' ,
'\'
UNION ALL
SELECT '\/' ,
'/'
UNION ALL
SELECT '\b' ,
CHAR(08)
UNION ALL
SELECT '\f' ,
CHAR(12)
UNION ALL
SELECT '\n' ,
CHAR(10)
UNION ALL
SELECT '\r' ,
CHAR(13)
UNION ALL
SELECT '\t' ,
CHAR(09)
) substitutions; SELECT @result = 0 ,
@Escape = 1; --Begin to take out any hex escape codes WHILE @Escape > 0
BEGIN SELECT @index = 0 , --find the next hex escape sequence
@Escape = PATINDEX('%\x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%',
@token); IF @Escape > 0 --if there is one
BEGIN WHILE @index < 4 --there are always four digits to a \x sequence
BEGIN SELECT --determine its value
@result = @result + POWER(16,
@index)
* ( CHARINDEX(SUBSTRING(@token,
@Escape + 2 + 3
- @index, 1),
@characters) - 1 ) ,
@index = @index + 1; END; -- and replace the hex sequence by its unicode value SELECT @token = STUFF(@token, @Escape, 6,
NCHAR(@result)); END; END; --now store the string away INSERT INTO @Strings
( StringValue )
SELECT @token; -- and replace the string with a token SELECT @JSON = STUFF(@JSON, @Start, @end + 1,
'@string'
+ CONVERT(NVARCHAR(5), @@identity)); END; -- all strings are now removed. Now we find the first leaf. WHILE 1 = 1 --forever until there is nothing more to do
BEGIN SELECT @parent_ID = @parent_ID + 1; --find the first object or list by looking for the open bracket SELECT @FirstObject = PATINDEX('%[{[[]%',
@JSON COLLATE SQL_Latin1_General_CP850_BIN);--object or array IF @FirstObject = 0
BREAK; IF ( SUBSTRING(@JSON, @FirstObject, 1) = '{' )
SELECT @NextCloseDelimiterChar = '}' ,
@Type = 'object'; ELSE
SELECT @NextCloseDelimiterChar = ']' ,
@Type = 'array'; SELECT @OpenDelimiter = @FirstObject; WHILE 1 = 1 --find the innermost object or list...
BEGIN SELECT @lenJSON = LEN(@JSON + '|') - 1; --find the matching close-delimiter proceeding after the open-delimiter SELECT @NextCloseDelimiter = CHARINDEX(@NextCloseDelimiterChar,
@JSON,
@OpenDelimiter
+ 1); --is there an intervening open-delimiter of either type SELECT @NextOpenDelimiter = PATINDEX('%[{[[]%',
RIGHT(@JSON,
@lenJSON
- @OpenDelimiter)COLLATE SQL_Latin1_General_CP850_BIN);--object IF @NextOpenDelimiter = 0
BREAK; SELECT @NextOpenDelimiter = @NextOpenDelimiter
+ @OpenDelimiter; IF @NextCloseDelimiter < @NextOpenDelimiter
BREAK; IF SUBSTRING(@JSON, @NextOpenDelimiter, 1) = '{'
SELECT @NextCloseDelimiterChar = '}' ,
@Type = 'object'; ELSE
SELECT @NextCloseDelimiterChar = ']' ,
@Type = 'array'; SELECT @OpenDelimiter = @NextOpenDelimiter; END; ---and parse out the list or name/value pairs SELECT @Contents = SUBSTRING(@JSON, @OpenDelimiter + 1,
@NextCloseDelimiter
- @OpenDelimiter - 1); SELECT @JSON = STUFF(@JSON, @OpenDelimiter,
@NextCloseDelimiter - @OpenDelimiter + 1,
'@' + @Type
+ CONVERT(NVARCHAR(5), @parent_ID)); WHILE ( PATINDEX('%[A-Za-z0-9@+.e]%',
@Contents COLLATE SQL_Latin1_General_CP850_BIN) ) <> 0
BEGIN IF @Type = 'Object' --it will be a 0-n list containing a string followed by a string, number,boolean, or null
BEGIN SELECT @SequenceNo = 0 ,
@end = CHARINDEX(':', ' ' + @Contents);--if there is anything, it will be a string-based name. SELECT @Start = PATINDEX('%[^A-Za-z@][@]%',
' ' + @Contents);--AAAAAAAA SELECT @token = SUBSTRING(' ' + @Contents,
@Start + 1,
@end - @Start - 1) ,
@EndOfName = PATINDEX('%[0-9]%',
@token COLLATE SQL_Latin1_General_CP850_BIN) ,
@param = RIGHT(@token,
LEN(@token)
- @EndOfName + 1); SELECT @token = LEFT(@token, @EndOfName - 1) ,
@Contents = RIGHT(' ' + @Contents,
LEN(' ' + @Contents
+ '|') - @end
- 1); SELECT @name = StringValue
FROM @Strings
WHERE String_ID = @param; --fetch the name END; ELSE
SELECT @name = NULL ,
@SequenceNo = @SequenceNo + 1; SELECT @end = CHARINDEX(',', @Contents);-- a string-token, object-token, list-token, number,boolean, or null IF @end = 0
SELECT @end = PATINDEX('%[A-Za-z0-9@+.e][^A-Za-z0-9@+.e]%',
@Contents + ' ') + 1; SELECT @Start = PATINDEX('%[^A-Za-z0-9@+.e][A-Za-z0-9@+.e]%',
' ' + @Contents); --select @start,@end, LEN(@contents+'|'), @contents SELECT @value = RTRIM(SUBSTRING(@Contents, @Start,
@end - @Start)) ,
@Contents = RIGHT(@Contents + ' ',
LEN(@Contents + '|') - @end); IF SUBSTRING(@value, 1, 7) = '@object'
INSERT INTO @hierarchy
( NAME ,
sequenceNo ,
parent_ID ,
StringValue ,
Object_ID ,
ValueType
)
SELECT @name ,
@SequenceNo ,
@parent_ID ,
SUBSTRING(@value, 8, 5) ,
SUBSTRING(@value, 8, 5) ,
'object'; ELSE
IF SUBSTRING(@value, 1, 6) = '@array'
INSERT INTO @hierarchy
( NAME ,
sequenceNo ,
parent_ID ,
StringValue ,
Object_ID ,
ValueType
)
SELECT @name ,
@SequenceNo ,
@parent_ID ,
SUBSTRING(@value, 7, 5) ,
SUBSTRING(@value, 7, 5) ,
'array'; ELSE
IF SUBSTRING(@value, 1, 7) = '@string'
INSERT INTO @hierarchy
( NAME ,
sequenceNo ,
parent_ID ,
StringValue ,
ValueType
)
SELECT @name ,
@SequenceNo ,
@parent_ID ,
StringValue ,
'string'
FROM @Strings
WHERE String_ID = SUBSTRING(@value,
8, 5); ELSE
IF @value IN ( 'true', 'false' )
INSERT INTO @hierarchy
( NAME ,
sequenceNo ,
parent_ID ,
StringValue ,
ValueType
)
SELECT @name ,
@SequenceNo ,
@parent_ID ,
@value ,
'boolean'; ELSE
IF @value = 'null'
INSERT INTO @hierarchy
( NAME ,
sequenceNo ,
parent_ID ,
StringValue ,
ValueType
)
SELECT @name ,
@SequenceNo ,
@parent_ID ,
@value ,
'null'; ELSE
IF PATINDEX('%[^0-9]%',
@value COLLATE SQL_Latin1_General_CP850_BIN) > 0
INSERT INTO @hierarchy
( NAME ,
sequenceNo ,
parent_ID ,
StringValue ,
ValueType
)
SELECT
@name ,
@SequenceNo ,
@parent_ID ,
@value ,
'real'; ELSE
INSERT INTO @hierarchy
( NAME ,
sequenceNo ,
parent_ID ,
StringValue ,
ValueType
)
SELECT
@name ,
@SequenceNo ,
@parent_ID ,
@value ,
'int'; IF @Contents = ' '
SELECT @SequenceNo = 0; END; END; INSERT INTO @hierarchy
( NAME ,
sequenceNo ,
parent_ID ,
StringValue ,
Object_ID ,
ValueType
)
SELECT '-' ,
1 ,
NULL ,
'' ,
@parent_ID - 1 ,
@Type; -- RETURN; END;
在SqlServer 中解析JSON数据 [parseJSON] 函数 数据库中 解析JSON的更多相关文章
- 使用SqlBulkCopy, 插入整个DataTable中的所有数据到指定数据库中
string sql=""; dbhelper.ExecuteNonQuery(sql); DataTable dt = dbhelper.GetDataTable(sql); i ...
- 将Excel上千条数据写入到数据库中
简要说明:因工作需要,需要一张Excel表格中的所有数据导入到数据库中.如下表,当然这只是一部分,一共一千多条. 前期处理: 首先要保证上图中的Excel表格中的数据不能为空,如果有为空的数据,可以稍 ...
- 通过js获取前台数据向一般处理程序传递Json数据,并解析Json数据,将前台传来的Json数据写入数据库表中
摘自:http://blog.csdn.net/mazhaojuan/article/details/8592015 通过js获取前台数据向一般处理程序传递Json数据,并解析Json数据,将前台传来 ...
- 截取HTML中的JSON数据并利用GSON进行解析(Android)
截取HTML中的JSON数据并利用GSON进行解析(Android) 前言 最近在做的一个Android项目,需要自行搭建服务器,队友选择买了阿里云的服务器ESC产品,在数据获取上,我们采用了Andr ...
- iOS key value coding kvc在接收json数据与 model封装中的使用
iOS key value coding kvc在接收json数据与 model封装中的使用 使用 kvc 能够极大的简化代码工作,及以后的接口维护工作: 1:先创建MovieModel类.h和 . ...
- 用python导入20个G的json数据到Mysql数据库
整体思路参考资料:https://blog.csdn.net/layman2016/article/details/79252499 作业:有一个16个G的跟疫情相关的json新闻大数据(articl ...
- ASP.NET MVC搭建项目后台UI框架—8、将View中选择的数据行中的部分数据传入到Controller中
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
- View中选择的数据行中的部分数据传入到Controller中
将View中选择的数据行中的部分数据传入到Controller中 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NE ...
- 多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中【我】
多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中 package com.xxx.xx.reve.service; import java.util.ArrayL ...
随机推荐
- 006.SMB之用户管理
一 用户添加 注意: 1 添加samba密码必须已经是系统用户,才能添加为samba用户. 2 samba账户密码可以和系统账号密码不一致(建议设为不同密码). 1.1 smbpasswd [root ...
- Python3 多元回归(包含属性的向量化)
# -*- coding: utf-8 -*- """ Created on Thu Jan 4 19:52:03 2018 @author: markli " ...
- JS脚本获取开发者后台所有Device
``` var ids = ["Device ID"]; var names = ["Device Name"]; $("td[aria-descri ...
- BZOJ.2125.最短路(仙人掌 最短路Dijkstra)
题目链接 多次询问求仙人掌上两点间的最短路径. 如果是在树上,那么求LCA就可以了. 先做着,看看能不能把它弄成树. 把仙人掌看作一个图(实际上就是),求一遍根节点到每个点的最短路dis[i]. 对于 ...
- BZOJ2973 : 石头游戏
考虑到$lcm(1,2,3,4,5,6)=60$,所以操作序列每60秒一个循环. 将操作表示成转移矩阵的形式,预处理出前60秒的转移矩阵以及它们的乘积$B$. 那么t秒的转移矩阵为前$t\bmod 6 ...
- hdu 5768 Lucky7 容斥
Lucky7 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5768 Description When ?? was born, seven crow ...
- Java Web c3p0 pool池泄漏优化与日志分析
问题跟踪: 近期在整合SSH(spring.springmvc.hibernate)项目,提供给第三方服务.每当调用内存池达到上限之后,外界调用服务直接失败,提示[cannot open connec ...
- CentOS 7下使用chkconfig添加的服务无法使用/etc/profile里面的环境变量
经过分析/etc/profile为入口的,基本是登录后执行的变量,而使用chkconfig添加的服务多变以守护经常运行,没有登录. CentOS 7下使用chkconfig添加的服务无法使用/etc/ ...
- [Go] 跨平台文件系统监控工具 fsnotify 应用举例
项目地址:https://github.com/fsnotify/fsnotify fsnotify 能监控指定文件夹内 文件的修改情况,如 文件的 增加.删除.修改.重命名等操作. 官方给出了以下注 ...
- ThinkPHP 模型方法 setInc() 和 setDec() 使用详解
对于数字字段的加减,可以直接使用 setInc() 与 setDec() 方法 ThinkPHP 内置了对统计数据(数字字段)的更新方法: setInc():将数字字段值增加 setDec():将数字 ...