我有一个表,其中有一个包含JSON数据的列。每列中的每个JSON对象都有许多属性。我有另一个表,它的属性名称不是全部,而是很少。
我需要做的是编写一个查询以从表中选择JSON数据,但是JSON不应该包含第二个表中的属性。例如,下面是jSON表。
Id Person
1 {FirstName:"test", LastName: "test", Email: "test@test.abc"}
2 {FirstName:"syx", LastName: "ave", Email: "yyeyd@test.abc"}
具有属性名称的第二张表:
ExclusionId ExcludedProperty
1 Email
查询应将这两个表连接起来,输出应为
Id Person
1 {FirstName:"test", LastName: "test"}
2 {FirstName:"syx", LastName: "ave"}
答案 0 :(得分:7)
使用已更正的JSON,您可以使用JSON_MODIFY()
并将所需值设置为NULL
示例
Declare @YourTable Table ([Id] int,[Person] varchar(500))
Insert Into @YourTable Values
(1,'{"FirstName":"test", "LastName": "test", "Email": "test@test.abc"}')
,(2,'{"FirstName":"syx", "LastName": "ave", "Email": "yyeyd@test.abc"}')
Select A.ID
,NewValue = JSON_MODIFY([Person],'$.Email',null)
From @YourTable A
返回
ID NewValue
1 {"FirstName":"test", "LastName": "test"}
2 {"FirstName":"syx", "LastName": "ave"}
答案 1 :(得分:2)
这是一种完全通用的方法,不需要动态SQL:
--a mockup to simulate your issue
--credits to John Cappelletti for the mockup-code
DECLARE @YourTable TABLE (Id INT,Person NVARCHAR(500))
INSERT INTO @YourTable VALUES
(1,'{"FirstName":"test", "LastName": "test", "Email": "test@test.abc"}')
,(2,'{"FirstName":"syx", "LastName": "ave", "Email": "yyeyd@test.abc"}');
DECLARE @ExcludeProperties TABLE (Id INT,PropName VARCHAR(500))
INSERT INTO @ExcludeProperties VALUES (1,'Email');
-查询
WITH cte AS
(
SELECT t.Id
,JsonValues.[key] AS PropName
,JsonValues.[value] AS PropValue
FROM @YourTable t
CROSS APPLY OPENJSON(t.Person) jsonValues
WHERE JsonValues.[key] COLLATE Latin1_General_CI_AS NOT IN(SELECT excl.PropName COLLATE Latin1_General_CI_AS FROm @ExcludeProperties excl)
)
SELECT cte.Id
,CONCAT('{',
STUFF((
SELECT CONCAT(',"',cte2.PropName,'":"',cte2.PropValue,'"')
FROM cte cte2
WHERE cte2.Id=cte.Id
FOR XML PATH('')
),1,1,'')
,'}')
FROM cte
GROUP BY cte.Id;
简而言之:
首先,我们使用CTE以EAV(实体-属性-值)的形式在JSON中创建所有属性的列表。这样,就可以轻松排除所有属性,在排除表中可以找到该名称。
由于我们不允许将列的值用作输出列的别名,因此可以使用字符串方法而不是FOR JSON
查询来构建JSON。
首先,我使用GROUP BY
将最终输出减少为 one-row-per-Id ,然后我使用相关的子查询从Id构建每个ID的JSON。相应的EAV。