SQLServer SQL函数解析JSON数据格式并返回表
SQLServer SQL函数解析JSON数据格式并返回表
SQL Code: --SQLServer SQL函数解析JSON数据格式并返回表 -- 数据库中 解析JSON ALTER FUNCTION [dbo].[ufn_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 /****************************************************************************** --测试普通JSON SELECT * FROM dbo.ufn_ParseJSON('{"url":"https://file.csframework.com/bankcark.jpg","descr":"银行卡"}') --测试数组JSON SELECT * FROM dbo.ufn_ParseJSON('[{"url":"https://file.csframework.com/bankcark1.jpg","descr":"银行卡1"},{"url":"https://file.csframework.com/bankcark2.jpg","descr":"银行卡2"}]') *******************************************************************************/ 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; //来源:C/S框架网(www.csframework.com) QQ:23404761 测试SQL函数: SQL Code: --测试普通JSON SELECT * FROM dbo.ufn_ParseJSON('{"url":"https://file.csframework.com/bankcark.jpg","descr":"银行卡"}') --测试数组JSON SELECT * FROM dbo.ufn_ParseJSON('[{"url":"https://file.csframework.com/bankcark1.jpg","descr":"银行卡1"},{"url":"https://file.csframework.com/bankcark2.jpg","descr":"银行卡2"}]') //来源:C/S框架网(www.csframework.com) QQ:23404761 返回结果:
参考文档:
将SQLServer数据类型转换为C#.Net类型 将SQLServer数据类型转换为.Net中SqlDbType类型 C#调用Delphi编译的DLL函数库返回大文本数据 SQLServer2005数据库转换成SQLServer2000 拔掉网线,无法连接本机SQLSERVER数据库 SQLServer附加数据库报错,错误:602 SQLSERVER 数据库查看各表的记录数 SQLServer 服务器主体无法在当前安全上下文下访问数据库 SQLServer数据库转移高版本转低版本(把2008R2的数据库备份为2005) SQL UPDATE语句关联表值函数(CROSS APPLY)关联更新数据 SQL脚本获取SQLServer数据库目录存储过程:f_GetDBPath SqlServer配置链接服务器LINKSERVER:ODBC连接MySQL数据库 C# C/S架构软件自动升级程序Winform+多数据库(MySQL,MsSQL,Oracle) C#源码-SQLServer数据库生成修改工具-源码下载 CSFramework.DB数据库组件SQL并发测试压力测试报告
其它资料:
什么是C/S结构? | C/S框架核心组成部分 | C/S框架-WebService部署图 | C/S框架-权限管理 | C/S结构系统框架 - 5.1旗舰版介绍 | C/S结构系统框架 - 功能介绍 | C/S结构系统框架 - 产品列表 | C/S结构系统框架 - 应用展示(图) | 三层体系架构详解 | C/S架构轻量级快速开发框架 | C/S框架网客户案例 | WebApi快速开发框架 | C/S框架代码生成器 | 用户授权注册软件系统 | 版本自动升级软件 | 数据库底层应用框架 | CSFramework.CMS内容管理系统 | |