使用 JSON_VALUE 访问 SQL Server 2016 中的 JSON 数组

Posted

技术标签:

【中文标题】使用 JSON_VALUE 访问 SQL Server 2016 中的 JSON 数组【英文标题】:Accessing JSON Array in SQL Server 2016 using JSON_VALUE 【发布时间】:2016-11-12 02:50:45 【问题描述】:

我在使用新引入的 JSON_VALUE 函数访问 json 中的数组时卡住了。请考虑以下代码 -

IF EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='JsonData')
    DROP TABLE JsonData;
go

CREATE TABLE JsonData(JsonData nvarchar(max));
DECLARE @SQL nvarchar(max);
DECLARE @Table AS TABLE(JsonPath VARCHAR(256));

INSERT INTO JsonData(JsonData)
VALUES(
'
  "firstName": "John",
  "lastName" : "doe",
  "age"      : 26,
  "address"  : 
    "streetAddress": "naist street",
    "city"         : "Nara",
    "postalCode"   : "630-0192"
  ,
  "phoneNumbers": [
    
      "type"  : "iPhone",
      "number": "0123-4567-8888"
    ,
    
      "type"  : "home",
      "number": "0123-4567-8910"
    
  ]
')


INSERT INTO @Table
SELECT VALUE  FROM OPENJSON('
"Path1":"$.firstName","Path2":"$.phoneNumbers[:1].number"
') ;

SELECT  @SQL=(SELECT 'UNION SELECT '''+ CAST(JsonPath AS VARCHAR(256)) +''',JSON_VALUE(JsonData,'''+a.JsonPath+''')  
                    FROM JsonData a'                             
                    FROM @Table a       
        FOR XML PATH(''), TYPE)
    .value('.','NVARCHAR(MAX)')
FROM @Table t;

SELECT @SQL=RIGHT(@SQL,LEN(@SQL)-5)

PRINT @SQL    

EXEC SP_EXECUTESQL @SQL;

这里如果我想访问特定的电话号码,那么访问此节点的常规语法不起作用。在这种情况下,我收到以下错误

JSON path is not properly formatted. Unexpected character ':' is found at position 15.

虽然当我检查 http://jsonpath.com 时,我能够检索值。 SQL Server 2016 是否使用一些不同的语法来访问 JSON 值?

【问题讨论】:

这是题外话,但知道可能有用。您可以使用 DROP TABLE IF EXISTS JsonData 而不是 if (select) drop table.... 同意,旧习惯很难改掉 :-) 【参考方案1】:

从 phoneNumbers 获取所有信息:

DECLARE @json nvarchar(max)=
    '
      "firstName": "John",
      "lastName" : "doe",
      "age"      : 26,
      "address"  : 
        "streetAddress": "naist street",
        "city"         : "Nara",
        "postalCode"   : "630-0192"
      ,
      "phoneNumbers": [
        
          "type"  : "iPhone",
          "number": "0123-4567-8888"
        ,
        
          "type"  : "home",
          "number": "0123-4567-8910"
        
      ]
    '

    SELECT [Type], [Number]
    FROM OPENJSON( @json, '$.phoneNumbers' ) 
    WITH ([Type] NVARCHAR(25) '$.type', [Number] NVARCHAR(25) '$.number');

【讨论】:

再次感谢!看起来它是我能得到的最接近的。如果我不知道所提供 JSON 的确切结构,则需要进行大量调整,但您的建议帮助我朝着正确的方向前进。我想创建通用解决方案。我希望将来的更新可以支持正确的 JSON 遍历。【参考方案2】:

您可以使用“CROSS APPLY”获取带有名字的电话号码:

SELECT  JSON_VALUE (jsonData, '$.firstName'),p.*
    FROM JsonData
    CROSS APPLY
    OPENJSON (JsonData, '$.phoneNumbers') WITH(type varchar(10) '$.type', number varchar (30) '$.number') p

【讨论】:

【参考方案3】:

SQL Server 2016 支持 JSON。它非常相似,几乎完全相同。您将自己进行比较。

您不需要使用临时变量@Table 然后进行操作...

只需运行以下查询

SELECT  JSON_VALUE( JsonData, '$.phoneNumbers[0].type' ) AS [PhoneType], 
        JSON_VALUE( JsonData, '$.phoneNumbers[0].number' ) AS [PhoneNumber]
FROM JsonData
WHERE ISJSON( JsonData ) > 0;
--iPhone 0123-4567-8888

SELECT  JSON_VALUE( JsonData, '$.phoneNumbers[1].type' ) AS [PhoneType], 
        JSON_VALUE( JsonData, '$.phoneNumbers[1].number' ) AS [PhoneNumber]
FROM JsonData
WHERE ISJSON( JsonData ) > 0;
--home  0123-4567-8910

查看这些来自 Microsoft 的官方链接,了解更多关于 JSON 支持的详细信息:

https://msdn.microsoft.com/en-us/library/dn921897.aspx

https://msdn.microsoft.com/en-us/library/dn921898.aspx

【讨论】:

您好,感谢您的帮助!我需要 @table 变量,因为我的原始解决方案需要一个参数,应用程序可以在其中传递任何 JSON 路径。应该从(非常)复杂的 JSON 返回针对该传递路径的数据。它是一个简化的示例,如果数组作为参数提供,我基本上需要返回所有元素。例如,$.phoneNumbers[:].number 应该返回该数组中的所有数字。 Aham,那么您已经非常接近解决方案了。当您在查询中尝试时,我会在动态 sql 查询中使用上述查询(或路径)。知道 T-SQL JSON 中的 $.phoneNumbers[:] 实际上是 $.phoneNumbers[*] 再次感谢!当我尝试使用 * 时出现以下错误 - Msg 13607, Level 16, State 4, Line 4 JSON 路径格式不正确。在第 15 位发现意外字符“*”。如果您能指出任何解释“TSQL JSON”的链接,那将非常有帮助。我找不到任何这样的参考 '[*]' 是错误的语法。我没有测试它(假设 [:] 有效,并且期望 [*] 也有效。有关如何获取所有行的信息,请参阅下面的帖子。那么您必须使用 OPENJSON。 谢谢,JSON_VALUE(c.value,'$.stock_asset_rents[0].sequence_num') as [stock_asset_rents_sequence_num],努力访问json数组【参考方案4】:

一起来。

DECLARE @json NVARCHAR(MAX)
    = '
      "firstName": "John",
      "lastName" : "doe",
      "age"      : 26,
      "address"  : 
        "streetAddress": "naist street",
        "city"         : "Nara",
        "postalCode"   : "630-0192"
      ,
      "phoneNumbers": [
        
          "type"  : "iPhone",
          "number": "0123-4567-8888"
        ,
        
          "type"  : "home",
          "number": "0123-4567-8910"
        
      ]
    ';

SELECT
    Core.*
   ,ARRAY.[Type]
   ,ARRAY.[Number]
FROM
    OPENJSON(@json)
        WITH
        (
            FirstName NVARCHAR(25) '$.firstName'
           ,LastName NVARCHAR(25) '$.lastName'
           ,Age INT '$.age'
           ,streetAddress NVARCHAR(25) '$.address.streetAddress'
           ,city NVARCHAR(25) '$.address.city'
        ) AS Core
    CROSS APPLY
    OPENJSON(@json, '$.phoneNumbers')
        WITH
        (
            [Type] NVARCHAR(25) '$.type'
           ,[Number] NVARCHAR(25) '$.number'
        ) AS ARRAY;

【讨论】:

以上是关于使用 JSON_VALUE 访问 SQL Server 2016 中的 JSON 数组的主要内容,如果未能解决你的问题,请参考以下文章

多个节点同名时使用 Oracle SQL 获取 JSON_VALUE

sql MS SQL JSON_VALUE

在 PL/SQL 中出现错误“PLS-00201:必须声明标识符‘JSON_VALUE’”

SQL Server JSON_VALUE 语法

EFCore使用JSON_VALUE查询json对象的值

如何将 Oracle 的 JSON_VALUE 函数与 PreparedStatement 一起使用