json数组到表
Posted
技术标签:
【中文标题】json数组到表【英文标题】:json array to table 【发布时间】:2018-06-02 15:33:31 【问题描述】:我使用的是 SQL Server 2014。我无法使用openjson
读取以下数组并将其转换为表结构。我的数组如下所示。它可以有两个以上的对象。我在表中还有一些其他列 (tableA
) 以及数组列:
["Id":1725,"Number":"12345","qty":1,"Block":true,
"Id":125,"Number":"1234544","qty":1,"Block":true]
在下面创建函数。
但是当我为我的表运行它时它返回空白-
SELECT
dbo.fn_parse_json2xml(X.jsoncolumn) AS XML_Column
FROM
tableA AS X;
我无法让它工作。如果我错过了什么,我提前道歉。
CREATE FUNCTION dbo.fn_parse_json2xml(
@json varchar(max)
)
RETURNS xml
AS
BEGIN;
DECLARE @output varchar(max), @key varchar(max), @value varchar(max),
@recursion_counter int, @offset int, @nested bit, @array bit,
@tab char(1)=CHAR(9), @cr char(1)=CHAR(13), @lf char(1)=CHAR(10);
--- Clean up the JSON syntax by removing line breaks and tabs and
--- trimming the results of leading and trailing spaces:
SET @json=LTRIM(RTRIM(
REPLACE(REPLACE(REPLACE(@json, @cr, ''), @lf, ''), @tab, '')));
--- Sanity check: If this is not valid JSON syntax, exit here.
IF (LEFT(@json, 1)!='' OR RIGHT(@json, 1)!='')
RETURN '';
--- Because the first and last characters will, by definition, be
--- curly brackets, we can remove them here, and trim the result.
SET @json=LTRIM(RTRIM(SUBSTRING(@json, 2, LEN(@json)-2)));
SELECT @output='';
WHILE (@json!='') BEGIN;
--- Look for the first key which should start with a quote.
IF (LEFT(@json, 1)!='"')
RETURN 'Expected quote (start of key name). Found "'+
LEFT(@json, 1)+'"';
--- .. and end with the next quote (that isn't escaped with
--- and backslash).
SET @key=SUBSTRING(@json, 2,
PATINDEX('%[^\\]"%', SUBSTRING(@json, 2, LEN(@json))+' "'));
--- Truncate @json with the length of the key.
SET @json=LTRIM(SUBSTRING(@json, LEN(@key)+3, LEN(@json)));
--- The next character should be a colon.
IF (LEFT(@json, 1)!=':')
RETURN 'Expected ":" after key name, found "'+
LEFT(@json, 1)+'"!';
--- Truncate @json to skip past the colon:
SET @json=LTRIM(SUBSTRING(@json, 2, LEN(@json)));
--- If the next character is an angle bracket, this is an array.
IF (LEFT(@json, 1)='[')
SELECT @array=1, @json=LTRIM(SUBSTRING(@json, 2, LEN(@json)));
IF (@array IS NULL) SET @array=0;
WHILE (@array IS NOT NULL) BEGIN;
SELECT @value=NULL, @nested=0;
--- The first character of the remainder of @json indicates
--- what type of value this is.
--- Set @value, depending on what type of value we're looking at:
---
--- 1. A new JSON object:
--- To be sent recursively back into the parser:
IF (@value IS NULL AND LEFT(@json, 1)='') BEGIN;
SELECT @recursion_counter=1, @offset=1;
WHILE (@recursion_counter!=0 AND @offset<LEN(@json)) BEGIN;
SET @offset=@offset+
PATINDEX('%[]%', SUBSTRING(@json, @offset+1,
LEN(@json)));
SET @recursion_counter=@recursion_counter+
(CASE SUBSTRING(@json, @offset, 1)
WHEN '' THEN 1
WHEN '' THEN -1 END);
END;
SET @value=CAST(
dbo.fn_parse_json2xml(LEFT(@json, @offset))
AS varchar(max));
SET @json=SUBSTRING(@json, @offset+1, LEN(@json));
SET @nested=1;
END
--- 2a. Blank text (quoted)
IF (@value IS NULL AND LEFT(@json, 2)='""')
SELECT @value='', @json=LTRIM(SUBSTRING(@json, 3,
LEN(@json)));
--- 2b. Other text (quoted, but not blank)
IF (@value IS NULL AND LEFT(@json, 1)='"') BEGIN;
SET @value=SUBSTRING(@json, 2,
PATINDEX('%[^\\]"%',
SUBSTRING(@json, 2, LEN(@json))+' "'));
SET @json=LTRIM(
SUBSTRING(@json, LEN(@value)+3, LEN(@json)));
END;
--- 3. Blank (not quoted)
IF (@value IS NULL AND LEFT(@json, 1)=',')
SET @value='';
--- 4. Or unescaped numbers or text.
IF (@value IS NULL) BEGIN;
SET @value=LEFT(@json,
PATINDEX('%[,]%', REPLACE(@json, ']', '')+'')-1);
SET @json=SUBSTRING(@json, LEN(@value)+1, LEN(@json));
END;
--- Append @key and @value to @output:
SET @output=@output+@lf+@cr+
REPLICATE(@tab, @@NESTLEVEL-1)+
'<'+@key+'>'+
ISNULL(REPLACE(
REPLACE(@value, '\"', '"'), '\\', '\'), '')+
(CASE WHEN @nested=1
THEN @lf+@cr+REPLICATE(@tab, @@NESTLEVEL-1)
ELSE ''
END)+
'</'+@key+'>';
--- And again, error checks:
---
--- 1. If these are multiple values, the next character
--- should be a comma:
IF (@array=0 AND @json!='' AND LEFT(@json, 1)!=',')
RETURN @output+'Expected "," after value, found "'+
LEFT(@json, 1)+'"!';
--- 2. .. or, if this is an array, the next character
--- should be a comma or a closing angle bracket:
IF (@array=1 AND LEFT(@json, 1) NOT IN (',', ']'))
RETURN @output+'In array, expected "]" or "," after '+
'value, found "'+LEFT(@json, 1)+'"!';
--- If this is where the array is closed (i.e. if it's a
--- closing angle bracket)..
IF (@array=1 AND LEFT(@json, 1)=']') BEGIN;
SET @array=NULL;
SET @json=LTRIM(SUBSTRING(@json, 2, LEN(@json)));
--- After a closed array, there should be a comma:
IF (LEFT(@json, 1) NOT IN ('', ',')) BEGIN
RETURN 'Closed array, expected ","!';
END;
END;
SET @json=LTRIM(SUBSTRING(@json, 2, LEN(@json)+1));
IF (@array=0) SET @array=NULL;
END;
END;
--- Return the output:
RETURN CAST(@output AS xml);
END;
DECLARE @json varchar(max);
SET @json='
"Person":
"firstName": "John",
"lastName": "Smith",
"age": [25, 26, 27],
"Address":
"streetAddress":"21, 2nd Street",
"city" :"New York",
"state":"NY",
"postalCode":"10021"
,
"PhoneNumbers":
"home":"212 555-1234",
"fax":"646 555-4567"
';
SELECT dbo.fn_parse_json2xml(@json);
【问题讨论】:
请编辑您的问题并包含fn_parse_json2xml()
的代码。
它在链接中。我还需要包含它吗?
我在该链接中看不到名为 fn_parse_json2xml
的函数。有一个叫做parseJSON
,但是,这是一个多行表值函数,您似乎在使用标量函数。
显示 you 实际拥有的内容,因为错误很可能就在其中。此外,链接文章中没有fn_parse_json2xml
,不要让我们猜测您已将其重命名为什么。除此之外,该链接可能会失效,以便为未来的读者提供帖子中的所有重要内容。始终保留一个exe文件。仅将链接用于进一步阅读,并在帖子中包含您的问题实际涉及的内容。
添加了它。很抱歉造成混乱。
【参考方案1】:
这个答案真的很晚,可能对你来说太晚了,但它可能对其他人有帮助:
假设结构始终相同,您可以轻松地将字符串转换为 XML:
DECLARE @jsonString NVARCHAR(MAX)=
N'["Id":1725,"Number":"12345","qty":1,"Block":true,
"Id":125,"Number":"1234544","qty":1,"Block":true]';
DECLARE @Converted XML=
CAST(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(@jsonString,'[','')
,'"Id":','<row><Id>')
,',"Number":','</Id><Number>')
,',"qty":','</Number><qty>')
,',"Block":','</qty><Block>')
,',','</Block></row>')
,']','</Block></row>') AS XML);
--查看结果
SELECT @Converted;
<row>
<Id>1725</Id>
<Number>"12345"</Number>
<qty>1</qty>
<Block>true</Block>
</row>
<row>
<Id>125</Id>
<Number>"1234544"</Number>
<qty>1</qty>
<Block>true</Block>
</row>
--这个 XML 可以像这里这样查询:
SELECT a.value('(Id/text())[1]','int') AS Id
,a.value('(Number/text())[1]','nvarchar(max)') AS Number
,a.value('(qty/text())[1]','int') AS qty
,a.value('(Block/text())[1]','bit') AS Block
FROM @Converted.nodes('/row') A(a);
最终结果
Id Number qty Block
1725 "12345" 1 1
125 "1234544" 1 1
【讨论】:
以上是关于json数组到表的主要内容,如果未能解决你的问题,请参考以下文章
通过 Mule 4 发送电子邮件时 JSON 数组到表结构格式