SQL解析传入的Json字符串

处理方式:将传入的Json字符串保存到表值函数中,读取表值函数中的数据

表值函数建立如下:

  1 CREATE FUNCTION [dbo].[parseJSON]
  2 (
  3 @Json NVARCHAR(MAX)
  4 )
  5 RETURNS @hierarchy TABLE 
  6 ( 
  7 element_id INT IDENTITY(1, 1) NOT NULL, /* internal surrogate primary key gives the order of parsing and the list order */ 
  8 sequenceNo [int] NULL, /* the place in the sequence for the element */ 
  9 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 */ 
 10 Object_ID INT,/* each list or object has an object id. This ties all elements to a parent. Lists are treated as objects here */ 
 11 NAME NVARCHAR(2000),/* the name of the object */ 
 12 StringValue NVARCHAR(MAX) NOT NULL,/*the string representation of the value of the element. */ 
 13 ValueType VARCHAR(10) NOT null /* the declared type of the value represented as a string in StringValue*/ 
 14 ) 
 15 AS
 16 BEGIN
 17 
 18 DECLARE 
 19 @FirstObject INT, --the index of the first open bracket found in the JSON string 
 20 @OpenDelimiter INT,--the index of the next open bracket found in the JSON string 
 21 @NextOpenDelimiter INT,--the index of subsequent open bracket found in the JSON string 
 22 @NextCloseDelimiter INT,--the index of subsequent close bracket found in the JSON string 
 23 @Type NVARCHAR(10),--whether it denotes an object or an array 
 24 @NextCloseDelimiterChar CHAR(1),--either a '}' or a ']' 
 25 @Contents NVARCHAR(MAX), --the unparsed contents of the bracketed expression 
 26 @Start INT, --index of the start of the token that you are parsing 
 27 @end INT,--index of the end of the token that you are parsing 
 28 @param INT,--the parameter at the end of the next Object/Array token 
 29 @EndOfName INT,--the index of the start of the parameter at end of Object/Array token 
 30 @token NVARCHAR(200),--either a string or object 
 31 @value NVARCHAR(MAX), -- the value as a string 
 32 @SequenceNo int, -- the sequence number within a list 
 33 @name NVARCHAR(200), --the name as a string 
 34 @parent_ID INT,--the next parent ID to allocate 
 35 @lenJSON INT,--the current length of the JSON String 
 36 @characters NCHAR(36),--used to convert hex to decimal 
 37 @result BIGINT,--the value of the hex symbol being parsed 
 38 @index SMALLINT,--used for parsing the hex value 
 39 @Escape INT --the index of the next escape character 
 40 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 */ 
 41 ( 
 42 String_ID INT IDENTITY(1, 1),StringValue NVARCHAR(MAX) 
 43 ) 
 44 SELECT--initialise the characters to convert hex to ascii 
 45 @characters='0123456789abcdefghijklmnopqrstuvwxyz', 
 46 @SequenceNo=0, --set the sequence no. to something sensible. 
 47 @parent_ID=0; 
 48 WHILE 1=1 --forever until there is nothing more to do 
 49 BEGIN 
 50 SELECT 
 51 @start=PATINDEX('%[^a-zA-Z]["]%', @json collate SQL_Latin1_General_CP850_Bin);--next delimited string 
 52 IF @start=0 BREAK --no more so drop through the WHILE loop 
 53 IF SUBSTRING(@json, @start+1, 1)='"' 
 54 BEGIN --Delimited Name 
 55 SET @start=@Start+1; 
 56 SET @end=PATINDEX('%[^]["]%', RIGHT(@json, LEN(@json+'|')-@start)); 
 57 END 
 58 IF @end=0 --no end delimiter to last string 
 59 BREAK --no more 
 60 SELECT @token=SUBSTRING(@json, @start+1, @end-1) 
 61 SELECT @token=REPLACE(@token, FROMString, TOString) 
 62 FROM 
 63 (SELECT 
 64 '"' AS FromString, '"' AS ToString 
 65 UNION ALL SELECT '\', '' 
 66 UNION ALL SELECT '/', '/' 
 67 UNION ALL SELECT '', CHAR(08) 
 68 UNION ALL SELECT 'f', CHAR(12) 
 69 UNION ALL SELECT '
', CHAR(10) 
 70 UNION ALL SELECT '
', CHAR(13) 
 71 UNION ALL SELECT '	', CHAR(09) 
 72 UNION ALL SELECT '', CHAR(09) 
 73 ) substitutions 
 74 SELECT @result=0,@escape=1 
 75 WHILE @escape>0 
 76 BEGIN 
 77 SELECT @index=0, 
 78 @escape=PATINDEX('%x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%', @token) 
 79 IF @escape>0 --if there is one 
 80 BEGIN 
 81 WHILE @index<4 --there are always four digits to a x sequence 
 82 BEGIN 
 83 SELECT --determine its value 
 84 @result=@result+POWER(16, @index) 
 85 *(CHARINDEX(SUBSTRING(@token, @escape+2+3-@index, 1), 
 86 @characters)-1), @index=@index+1 ; 
 87 END 
 88 SELECT @token=STUFF(@token, @escape, 6, NCHAR(@result)) 
 89 END 
 90 END 
 91 INSERT INTO @Strings (StringValue) SELECT @token 
 92 SELECT @JSON=STUFF(@json, @start, @end+1,'@string'+CONVERT(NVARCHAR(5), @@identity)) 
 93 END 
 94 WHILE 1=1 --forever until there is nothing more to do 
 95 BEGIN 
 96 SELECT @parent_ID=@parent_ID+1 
 97 SELECT @FirstObject=PATINDEX('%[{[[]%', @json collate SQL_Latin1_General_CP850_Bin)--object or array 
 98 IF @FirstObject = 0 BREAK 
 99 IF (SUBSTRING(@json, @FirstObject, 1)='{') 
100 SELECT @NextCloseDelimiterChar='}', @type='object' 
101 ELSE 
102 SELECT @NextCloseDelimiterChar=']', @type='array' 
103 SELECT @OpenDelimiter=@firstObject 
104 WHILE 1=1 --find the innermost object or list... 
105 BEGIN 
106 SELECT 
107 @lenJSON=LEN(@JSON+'|')-1 
108 SELECT 
109 @NextCloseDelimiter=CHARINDEX(@NextCloseDelimiterChar,@json,@OpenDelimiter+1) 
110 SELECT @NextOpenDelimiter=PATINDEX('%[{[[]%', 
111 RIGHT(@json, @lenJSON-@OpenDelimiter)collate SQL_Latin1_General_CP850_Bin)--object 
112 IF @NextOpenDelimiter=0 
113 BREAK 
114 SELECT @NextOpenDelimiter=@NextOpenDelimiter+@OpenDelimiter 
115 IF @NextCloseDelimiter<@NextOpenDelimiter 
116 BREAK 
117 IF SUBSTRING(@json, @NextOpenDelimiter, 1)='{' 
118 SELECT @NextCloseDelimiterChar='}', @type='object' 
119 ELSE 
120 SELECT @NextCloseDelimiterChar=']', @type='array' 
121 SELECT @OpenDelimiter=@NextOpenDelimiter 
122 END 
123 SELECT 
124 @contents=SUBSTRING(@json, @OpenDelimiter+1,@NextCloseDelimiter-@OpenDelimiter-1) 
125 SELECT 
126 @JSON=STUFF(@json, @OpenDelimiter,@NextCloseDelimiter-@OpenDelimiter+1,'@'+@type+CONVERT(NVARCHAR(5), @parent_ID)) 
127 WHILE (PATINDEX('%[A-Za-z0-9@+.e]%', @contents collate SQL_Latin1_General_CP850_Bin))<>0 
128 BEGIN 
129 IF @Type='Object' --it will be a 0-n list containing a string followed by a string, number,boolean, or null 
130 BEGIN 
131 SELECT 
132 @SequenceNo=0,@end=CHARINDEX(':', ' '+@contents)--if there is anything, it will be a string-based name. 
133 SELECT @start=PATINDEX('%[^A-Za-z@][@]%', ' '+@contents)--AAAAAAAA 
134 SELECT @token=SUBSTRING(' '+@contents, @start+1, @End-@Start-1), 
135 @endofname=PATINDEX('%[0-9]%', @token collate SQL_Latin1_General_CP850_Bin), 
136 @param=RIGHT(@token, LEN(@token)-@endofname+1) 
137 SELECT 
138 @token=LEFT(@token, @endofname-1), 
139 @Contents=RIGHT(' '+@contents, LEN(' '+@contents+'|')-@end-1) 
140 SELECT @name=stringvalue FROM @strings 
141 WHERE string_id=@param --fetch the name 
142 END 
143 ELSE 
144 SELECT @Name=null,@SequenceNo=@SequenceNo+1 
145 SELECT 
146 @end=CHARINDEX(',', @contents)-- a string-token, object-token, list-token, number,boolean, or null 
147 IF @end=0 
148 SELECT @end=PATINDEX('%[A-Za-z0-9@+.e][^A-Za-z0-9@+.e]%', @Contents+' ') +1 
149 SELECT 
150 @start=PATINDEX('%[^A-Za-z0-9@+.e][A-Za-z0-9@+.e]%', ' '+@contents) 
151 --select @start,@end, LEN(@contents+'|'), @contents 
152 SELECT 
153 @Value=RTRIM(SUBSTRING(@contents, @start, @End-@Start)), 
154 @Contents=RIGHT(@contents+' ', LEN(@contents+'|')-@end) 
155 IF SUBSTRING(@value, 1, 7)='@object' 
156 INSERT INTO @hierarchy 
157 (NAME, SequenceNo, parent_ID, StringValue, Object_ID, ValueType) 
158 SELECT @name, @SequenceNo, @parent_ID, SUBSTRING(@value, 8, 5), 
159 SUBSTRING(@value, 8, 5), 'object' 
160 ELSE 
161 IF SUBSTRING(@value, 1, 6)='@array' 
162 INSERT INTO @hierarchy 
163 (NAME, SequenceNo, parent_ID, StringValue, Object_ID, ValueType) 
164 SELECT @name, @SequenceNo, @parent_ID, SUBSTRING(@value, 7, 5), 
165 SUBSTRING(@value, 7, 5), 'array' 
166 ELSE 
167 IF SUBSTRING(@value, 1, 7)='@string' 
168 INSERT INTO @hierarchy 
169 (NAME, SequenceNo, parent_ID, StringValue, ValueType) 
170 SELECT @name, @SequenceNo, @parent_ID, stringvalue, 'string' 
171 FROM @strings 
172 WHERE string_id=SUBSTRING(@value, 8, 5) 
173 ELSE 
174 IF @value IN ('true', 'false') 
175 INSERT INTO @hierarchy 
176 (NAME, SequenceNo, parent_ID, StringValue, ValueType) 
177 SELECT @name, @SequenceNo, @parent_ID, @value, 'boolean' 
178 ELSE 
179 IF @value='null' 
180 INSERT INTO @hierarchy 
181 (NAME, SequenceNo, parent_ID, StringValue, ValueType) 
182 SELECT @name, @SequenceNo, @parent_ID, @value, 'null' 
183 ELSE 
184 IF PATINDEX('%[^0-9]%', @value collate SQL_Latin1_General_CP850_Bin)>0 
185 INSERT INTO @hierarchy 
186 (NAME, SequenceNo, parent_ID, StringValue, ValueType) 
187 SELECT @name, @SequenceNo, @parent_ID, @value, 'real' 
188 ELSE 
189 INSERT INTO @hierarchy 
190 (NAME, SequenceNo, parent_ID, StringValue, ValueType) 
191 SELECT @name, @SequenceNo, @parent_ID, @value, 'int' 
192 
193 if @Contents=' ' Select @SequenceNo=0 
194 END 
195 END 
196 RETURN 
197 END

 

 

测试如下:

传入的Json字符串如下:

{
    "data":{
        "order_sn":"liaoning19032114523809671",
        "created_at":1553152116,
        "storeno":"SYS20170209014",
        "goods_amount":"3880.00",
        "order_amount":"3880.00",
        "points":"0.00",
        "pmt_amount":"64.20",
        "suppliers_name":"盘锦爱心电脑科技有限公司",
        "products":[
            {
                "sn":"90NB0E42-M02110",
                "number":"2",
                "price":"1940.00"
            }
        ],
        "coupon":[
            {
                "coupon_code":"As20190314140336018"
            },
            {
                "coupon_code":"As20190314140443050"
            }
        ],
        "user_id":5284
    }
}

 

使用表值函数后,查询到的数据入下:

 

 

 

 

原文地址:https://www.cnblogs.com/suflowers1700218/p/10577079.html