Bri*_* SP 4 sql sql-server recursion json sql-server-2016
我一直在阅读尽可能多的同一问题的问题和答案,但我想我的问题需要更多创造性的方法。
所以我这里有一个 JSON 字符串:
declare @json nvarchar(max) =
'{
"propertyObjects": [{
"propertyID": 1
, "title": "foo"
, "class": ""
, "typeid": 150
, "value": "bar"
, "children": [{}]
}, {
"propertyID": 2
, "title": "foo"
, "class": ""
, "typeid": 128
, "value": "bar"
, "children": [{}]
}, {
"propertyID": 3
, "title": "foo"
, "class": ""
, "typeid": 128
, "value": "bar"
, "children": [{
"propertyID": 4
, "title": "foo"
, "class": ""
, "typeid": 128
, "value": "bar"
, "children": [{}]
}, {
"propertyID": 5
, "title": "foo"
, "class": ""
, "typeid": 128
, "value": "bar"
, "children": [{}]
}, {
"propertyID": 6
, "title": "foo"
, "class": ""
, "typeid": 128
, "value": "bar"
, "children": [{
"propertyID": 7
, "title": "foo"
, "class": ""
, "typeid": 128
, "value": "bar"
, "children": [{
"propertyID": 8
, "title": "foo"
, "class": ""
, "typeid": 128
, "value": "bar"
, "children": [{}]
}]
}]
}]
}]
}'
Run Code Online (Sandbox Code Playgroud)
乍一看很疯狂,但可以这样想:
有一个名为propertyObjects的数组,它包含父子结构中的多个对象。
在每一层中,只有一个对象可以是父对象。正如你所看到的,对象 3 里面有孩子。
我在这里想要的是在表中列出这些对象,同时我们为每个对象指定一个 parentID,因此对象 4 有一个 ID 为 3 的父对象,而对象 3 本身的父对象为 0,因为它基本上位于顶层。
到目前为止,我尝试了一些像Common Table Expression这样的方法来进行递归调用,但我失败了:
;with cte
as
(
-- anchor member definition
select p.propertyID
, 0 as parentID
, p.title
, p.typeid
, p.[value]
, p.children
from openjson(@json, '$.propertyObjects')
with (
propertyID int
, title nvarchar(100)
, typeid int
, [value] nvarchar(1000)
, children nvarchar(max) as JSON
) as p
UNION ALL
-- recursive member definition
select 0 as propertyID
, 0 as parentID
, '' as title
, 0 typeid
, '' as [value]
, '' as children
/** child should be bound to parent **/
)
select * from cte
Run Code Online (Sandbox Code Playgroud)
这就是我失败的地方,我不知道如何让它通过孩子递归地找到对象。另外,我不知道如何指定每个孩子的 parentID!
propertyID parentID title typeid value children
----------------------------------------------------------------------------
1 0 foo 150 bar [{}]
2 0 foo 128 bar [{}]
3 0 foo 128 bar [{ "propertyID" : 4 ...
0 0 0
Run Code Online (Sandbox Code Playgroud)
我也尝试使用交叉应用:
select *
from
openjson(@json, '$.propertyObjects')
with (
propertyID int
, title nvarchar(100)
, typeid int
, [value] nvarchar(1000)
, children nvarchar(max) as JSON
) as p
cross apply
openjson(p.children)
with (
propertyID int
, title nvarchar(100)
, typeid int
, [value] nvarchar(1000)
, children nvarchar(max) as JSON
) as r
Run Code Online (Sandbox Code Playgroud)
但不是机会,我不知道这些孩子会在 JSON 字符串中深入到什么程度。此外,交叉应用的结果将附加列而不是行,这会导致结果中出现一个巨大的表,在这种方法中,我什至不能考虑指定 parentID。
这完全是一个失败,关于如何让所有孩子排成一行的任何想法?
所需表
propertyID parentID title typeid value
--------------------------------------------------
1 0 foo 150 bar
2 0 foo 128 bar
3 0 foo 128 bar
4 3 foo 128 bar
5 3 foo 128 bar
6 3 foo 128 bar
7 6 foo 128 bar
8 7 foo 128 bar
Run Code Online (Sandbox Code Playgroud)
您实际上非常接近 - 您只需要与以下CROSS APPLY一起使用OPENJSON:
with cte as (
select
p.propertyID,
0 as parentID,
p.title,
p.typeid,
p.[value],
p.children
from openjson(@json, '$.propertyObjects') with (
propertyID int,
title nvarchar(100),
typeid int,
[value] nvarchar(1000),
children nvarchar(max) as json
) as p
union all
select
p.propertyID,
c.propertyID,
p.title,
p.typeid,
p.[value],
p.children
from cte as c
cross apply openjson(c.children) with (
propertyID int,
title nvarchar(100),
typeid int,
[value] nvarchar(1000),
children nvarchar(max) as json
) as p
where
c.children <> '[{}]'
)
select
c.propertyID,
c.parentID,
c.title,
c.typeid,
c.value
from cte as c
Run Code Online (Sandbox Code Playgroud)