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 数组到表结构格式

Swift:动态地将 JSON 添加到表单元格数组中

如何将 Json 数据发送到表视图数组?迅速

Knockout JS:从 viewmodel 可观察数组创建 Json

如何使用vue js将数组中的数组检索到表中

当标题是键和值的混合时,将数据从 json 附加到表