在SQL Server 2012中使用JSON

在SQL Server 2012中使用JSON,sql,sql-server,json,Sql,Sql Server,Json,我正在从事一个项目,在这个项目中,我需要接收和使用的能力,即从接收到的JSON中提取信息。我正在使用的SQL Server的当前版本是2012年,在未来几年内不会更改,与2016版相比,该版本不包括对此的支持 我记得有人发过一篇帖子,他温和地提供了这方面的源代码,但不幸的是,他再也找不到了 这样做的想法是: 具有以下JSON: { "Obj1": { "Obj1_S_1": [{ "Obj1_S_1_S_1": "Blabla_1"

我正在从事一个项目,在这个项目中,我需要接收和使用的能力,即从接收到的JSON中提取信息。我正在使用的SQL Server的当前版本是2012年,在未来几年内不会更改,与2016版相比,该版本不包括对此的支持

我记得有人发过一篇帖子,他温和地提供了这方面的源代码,但不幸的是,他再也找不到了

这样做的想法是:

具有以下JSON:

{
    "Obj1": {
        "Obj1_S_1": [{
            "Obj1_S_1_S_1": "Blabla_1"
        }, {
            "Obj1_S_1_S_1": "Blabla_2"
        }, {
            "Obj1_S_1_S_1": "Blabla_3"
        }, {
            "Obj1_S_1_S_1": "Blabla_4"
        }, {
            "Obj1_S_1_S_1": "Blabla_5"
        }, {
            "Obj1_S_1_S_1": "Blabla_6"
        }]
    },
    "Obj2": "This is a simple string",
    "Obj3": "456.33"
}
我可以使用以下调用:

SET @My_Param = GET_JSON(@Source_JSON, '*.Obj1.Obj1_S_1[3].Obj1_S_1_S_1') ;
我会在变量@My_Param中输入值'Blabla_4'


顺便说一下,这与Oracle和MySQL中使用的语法完全相同。

可以通过一些策略性的解析/拆分操作来完成

样本数据

范例

带有解析/拆分自定义项的选项

不带解析/拆分自定义项的选项

如果需要的话,UDF

请参阅我的响应,其中我创建了一个与SQL 2012兼容的函数,该函数提取给定JSON和列名的值

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      Isaac Adams
-- Create date: 7/12/2018
-- Description: Give the JSON string and the name of the column from which you want the value
-- =============================================
CREATE FUNCTION JSON_VALUE
(
    @JSON NVARCHAR(3000),
    @column NVARCHAR(3000)
)
RETURNS NVARCHAR(3000)
AS
BEGIN

DECLARE @value NVARCHAR(3000);
DECLARE @trimmedJSON NVARCHAR(3000);

DECLARE @start INT;
DECLARE @length INT;

SET @start = PATINDEX('%' + @column + '":"%',@JSON) + LEN(@column) + 3;
SET @trimmedJSON = SUBSTRING(@JSON, @start, LEN(@JSON));
SET @length = PATINDEX('%", "%', @trimmedJSON);
SET @value = SUBSTRING(@trimmedJSON, 0, @length);

RETURN @value
END
GO

这是我所知道的实现2016年前消费JSON的最佳资源:,,谢谢@SqlZim的建议。我看过那个提议,但它不是我想要的,也许我还没有完全理解它。两个主要原因:1它遍历整个JSON,而不管您实际需要什么,也许只是第一个元素,2它将JSON转换为一种表,我的问题是,当JSON有6个不同层次结构时,结果会是什么,例如,数组中的数组中的数组……感谢John的帖子,但我认为它没有什么问题:1你提议将{/}和[/]都改为| | | | |从而失去结构和结构数组之间的区别;2假设存在层次结构,例如Obj2也是一个非常类似于Obj1的数组,您需要从这两个数组中的每个数组中查找特定元素。任何解决方案都必须尊重JSON的原始结构,我看不出您的建议是如何做到这一点的。也许,我错过了什么。。。是吗?虽然这个链接可以回答这个问题,但最好在这里包含答案的基本部分,并提供链接供参考。如果链接页面发生变化,只有链接的答案可能无效。@Prateek说得很好。我编辑了回复以包含重要方面。我会在以后的回复中记住这一点。谢谢@IsaacAdams的帖子。幸运的是,自从我发表最初的帖子以来,该公司决定转向SQL Server 2016,它已经对JSON消费提供了一些非常强大的本机支持。如果与您相关,我强烈建议您查看它,因为它的执行速度比我编写的任何代码都快200倍以上。给你几个数量级,当输入一个包含数组的80KB JSON时,它会在17ms内将整个数组转换成一个表。我认为这不能用SQL语言实现。干杯@这真是难以置信!谢谢你让我知道-这只是另一个让我的公司升级的好理由。
--Clean-up JSON String and add '|||' as a standard delimeter
Select @S = Replace(@S,MapFrm,MapTo)
 From (values ('"'     ,'')
             ,(char(13),'|||')
             ,(char(10),'|||')
             ,('}'     ,'|||')
             ,('{'     ,'|||')
             ,('['     ,'|||')
             ,(']'     ,'|||')
       ) b (MapFrm,MapTo)
Select Item  = left(RetVal,charindex(':',RetVal+':')-1)
      ,Value = ltrim(right(RetVal,len(RetVal)-charindex(':',RetVal+':')))
 From  [dbo].[udf-Str-Parse](@S,'|||')
 Where Len(IsNull(RetVal,' '))>1
 Order By RetSeq
Select Item  = left(RetVal,charindex(':',RetVal+':')-1)
      ,Value = ltrim(right(RetVal,len(RetVal)-charindex(':',RetVal+':')))
 From  (
        Select RetSeq = Row_Number() over (Order By (Select null))
              ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
        From  (Select x = Cast('<x>' + replace((Select replace(@S,'|||','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
        Cross Apply x.nodes('x') AS B(i)
       ) A
 Where Len(IsNull(RetVal,' '))>1
 Order By RetSeq
Item            Value
Obj1    
Obj1_S_1    
Obj1_S_1_S_1    Blabla_1
Obj1_S_1_S_1    Blabla_2
Obj1_S_1_S_1    Blabla_3
Obj1_S_1_S_1    Blabla_4
Obj1_S_1_S_1    Blabla_5
Obj1_S_1_S_1    Blabla_6
Obj2            This is a simple string,
Obj3            456.33
CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = Row_Number() over (Order By (Select null))
          ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From  (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i)
);
--Thanks Shnugo for making this XML safe
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
--Select * from [dbo].[udf-Str-Parse]('this,is,<test>,for,< & >',',')
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      Isaac Adams
-- Create date: 7/12/2018
-- Description: Give the JSON string and the name of the column from which you want the value
-- =============================================
CREATE FUNCTION JSON_VALUE
(
    @JSON NVARCHAR(3000),
    @column NVARCHAR(3000)
)
RETURNS NVARCHAR(3000)
AS
BEGIN

DECLARE @value NVARCHAR(3000);
DECLARE @trimmedJSON NVARCHAR(3000);

DECLARE @start INT;
DECLARE @length INT;

SET @start = PATINDEX('%' + @column + '":"%',@JSON) + LEN(@column) + 3;
SET @trimmedJSON = SUBSTRING(@JSON, @start, LEN(@JSON));
SET @length = PATINDEX('%", "%', @trimmedJSON);
SET @value = SUBSTRING(@trimmedJSON, 0, @length);

RETURN @value
END
GO