"expand"/加入 SQL select 通过 JSON 值在 MSSQL

"expand"/join SQL select by JSON values on MSSQL

我遇到了一个问题,我有一个 table,其中有两列包含 JSON 数据。我一直在阅读 Microsoft 关于在 MSSQL 中使用 JSON 的文档,但似乎无法解决我的具体问题。

考虑一下我的 table 中单行的这个相当简单的示例:

我想要实现的是将 LocationsJSONAssigneesJSON 中的值连接到自身上,并希望以这些方式结束:

看微软的文档好像是可以的,但我似乎无法正确处理问题。

JSON 支持已在 SQL Server 2016 中添加。您将无法解析早期版本中的 JSON 字符串。

您可以在 FROM 子句中将 CROSS APPLY 与 return 是 table 的任何函数一起使用,以对函数的结果执行交叉 "join"。在这种情况下,您需要的函数是 OPENJSON

以下代码:

declare @table table (id int, json1 nvarchar(max), json2 nvarchar(max))

insert into @table values (1,'["a","b"]','["1","2"]')

select id,vals1.value as V1,vals2.value as V2
from @table t 
    cross apply openjson(t.json1) vals1
    cross apply openjson(t.json2) vals2

会 return :

id  V1  V2
1   a   1
1   a   2
1   b   1
1   b   2

AND, 想到其他方式,这是较旧的样式 XML.nodes 方法与 apply CROSS JOIN

with cte as
(
    select 
       Id, Name, LocationJSON,
       cast(ltrim(replace(replace(replace(j.value('.', 'varchar(600)'), '{', ''), '}', ''), '"', ''))  as int)  Locations
    from
    (
       select Id, Name, LocationJSON,
         cast('<X>'+replace(LocationJSON, ',', '</X><X>')+'</X>' as xml) NLocationJSON 
       from table
    )a cross apply NLocationJSON.nodes ('/X') as Location(J)
), cte1 as
(
    select 
       Id, Name, AssigneesJSON,
       ltrim(replace(replace(replace(A.value('.', 'varchar(600)'), '{', ''), '}', ''), '"', ''))   Assignees
    from
    (
       select Id, Name, AssigneesJSON,
         cast('<X>'+replace(AssigneesJSON, ',', '</X><X>')+'</X>' as xml) NAssigneesJSON
       from table
    )a cross apply NAssigneesJSON.nodes ('/X') as Assignees(A)
)

select c.Id, c.Name, 
       c.LocationJSON, c1.AssigneesJSON, 
       c.Locations, c1.Assignees 
from cte c , cte1 c1 -- CROSS JOIN 

结果:

Id  Name    LocationJSON    AssigneesJSON   Locations   Assignees
100 Foo     {"123", "456"}  {"abc", "def"}  123         abc
100 Foo     {"123", "456"}  {"abc", "def"}  123         def
100 Foo     {"123", "456"}  {"abc", "def"}  456         abc
100 Foo     {"123", "456"}  {"abc", "def"}  456         def

最简单的解决方案是

DECLARE @MyTable TABLE  (Id  INT , [Name] VARCHAR(100),LocationsJSON VARCHAR(100) ,AssigneesJSON VARCHAR(100) )
INSERT INTO @MyTable
    SELECT * FROM 
    ( VALUES 
         (100,'Foo','["123","456"]','["abc","def"]' )

    )T (Id  , [Name] ,LocationsJSON  ,AssigneesJSON   )

    SELECT MT.Id, MT.Name,  MT.LocationsJSON ,MT.AssigneesJSON, R1.[value]  as Locations , R2.[value] as Assignees FROM @MyTable MT
    CROSS APPLY
    (
     SELECT * FROM OPENJSON(MT.LocationsJSON)
    )R1
    CROSS APPLY
    (
     SELECT * FROM OPENJSON(MT.AssigneesJSON)
    )R2

输出:

Id  Name    LocationsJSON   AssigneesJSON   Locations   Assignees
-----------------------------------------------------------------
100 Foo     ["123","456"]   ["abc","def"]   123         abc
100 Foo     ["123","456"]   ["abc","def"]   123         def
100 Foo     ["123","456"]   ["abc","def"]   456         abc
100 Foo     ["123","456"]   ["abc","def"]   456         def