7

我在将 Msft Sql Server 中的 JSON 函数网格在一起时遇到问题。我有一个存储复杂 JSON 结构的表,需要提取对象数组的子集。

例如,我制作了一个简单的脚本来创建一个表并用一些记录填充它:

CREATE TABLE JsonData ( CompanyId int IDENTITY(1,1) NOT NULL, Name varchar(50) NOT NULL, Json varchar(max) NOT NULL)

INSERT INTO JsonData (Name, Json) VALUES ('Company A', '{"Sector":"Food/Bev","EmployeeCount":105,"Address":{"Address1":"88 Oak Ave","Address2":"","City":"Madison","State":"WI","Zip":"11223"},"Vehicles":[{"Make":"Toyota","Model":"Camry","Year":2013,"Maintenance":[{"Desc":"Oil change","PerformedOn":"2017-04-01"},{"Desc":"Oil change","PerformedOn":"2017-08-01"}]},{"Make":"Ford","Model":"F150","Year":2010,"Maintenance":[{"Desc":"Oil change","PerformedOn":"2015-01-01"}]},{"Make":"Honda","Model":"Odyssey","Year":2010,"Maintenance":[{"Desc":"Oil change","PerformedOn":"2013-01-01"},{"Desc":"Oil change","PerformedOn":"2014-01-01"}]}]}');
INSERT INTO JsonData (Name, Json) VALUES ('Company B', '{"Sector":"Plastics","EmployeeCount":853,"Address":{"Address1":"100 Main St","Address2":"","City":"Anchorage","State":"AK","Zip":"56432"},"Vehicles":[{"Make":"Ford","Model":"F150","Year":2003,"Maintenance":[{"Desc":"Oil change","PerformedOn":"2017-01-01"},{"Desc":"Tire rotation","PerformedOn":"2017-01-01"},{"Desc":"Brake inspection","PerformedOn":"2017-02-01"}]},{"Make":"Ford","Model":"F150","Year":2008,"Maintenance":[{"Desc":"Oil change","PerformedOn":"2017-01-01"}]},{"Make":"Volkswagen","Model":"Jetta","Year":2010,"Maintenance":[]}]}');
INSERT INTO JsonData (Name, Json) VALUES ('Company C', '{"Sector":"Plastics","EmployeeCount":50,"Address":{"Address1":"99 Pine St","Address2":"","City":"Dallas","State":"TX","Zip":"33443"},"Vehicles":[{"Make":"Pontiac","Model":"Fiero","Year":1998,"Maintenance":[{"Desc":"Oil change","PerformedOn":"2010-04-01"},{"Desc":"Oil change","PerformedOn":"2000-08-01"}]},{"Make":"Chevy","Model":"Silverado","Year":2008,"Maintenance":[{"Desc":"Oil change","PerformedOn":"2010-01-01"}]},{"Make":"Honda","Model":"Odyssey","Year":2014,"Maintenance":[{"Desc":"Oil change","PerformedOn":"2015-04-01"},{"Desc":"Oil change","PerformedOn":"2015-09-01"}]}]}');

我正在尝试获取 B 公司的福特汽车清单。我的想法是获取公司 B 的记录,然后解析 json 以获取 Make = 'Ford' 的车辆数组。这个脚本有效,但它真的很笨重。

在我看来,这一切都应该汇总到一个单一的声明中。

DECLARE @vehicJson varchar(max);
SELECT @vehicJson = '{ "Vehicles": ' + JSON_QUERY(json, '$.Vehicles') + '}' FROM JsonData WHERE Name = 'Company B';
SELECT @vehicJson;
SELECT * FROM OPENJSON(@vehicJson, '$.Vehicles') WHERE JSON_VALUE(value, '$.Make') = 'Ford';

我看到的第一个问题是 JSON_QUERY 函数将我的对象数组作为字符串返回,但它不是纯 JSON。我手动为该字符串添加前缀和后缀,使其成为真正的 JSON 格式。
我尝试使用 For JSON PATH 输出真正的 JSON,但这不允许我将输出分配给变量。

下一个问题是 OPENJSON 正在处理一个字符串变量,它遵循我找到的所有 Msft 示例。我发现这些示例很奇怪,因为我假设大多数实际实现会将 JSON 存储在某种表中。

免责声明:我在上面示例中使用的 JSON 结构比我必须使用的格式简单得多。我正在考虑将结构分解为更简单的组件,然后在 Select 查询中构建最终的完整结构。性能也可能决定这种复杂结构的分解。我的意图是创建有助于将 JSON“非规范化”为更传统的 SQL 数据格式以进行调试和过滤的视图。

4

1 回答 1

11

查询显然会根据您的结构而改变,但我正在抽取您的样本。

OPENJSON可以将您的 JSON 分解为关系形式,以便您可以更轻松地过滤和选择。您可以使用可选WITH子句执行此操作:

SELECT j.*, j2.*
FROM JsonData j
CROSS APPLY OPENJSON(Json, '$.Vehicles') WITH (
    Make VARCHAR(10),
    Model VARCHAR(10),
    Year INT
) j2
WHERE j.Name = 'Company B'
    AND j2.Make = 'Ford'
;

您可以在不使用JSON_QUERYor的情况下走很长一段路JSON_VALUE。如您所说,上面可以在视图中使用,因此 Json 的东西是完全隐藏的。

字符串变量的情况可以通过将您的数据交叉应用到OPENJSON函数中轻松解决,如我在上面的代码中所示。

这会让你更接近你需要去的地方吗?

于 2018-02-27T17:16:54.050 回答