我在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的Fords车辆清单。我的想法是抓住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查询中构建最终的完整结构。表现也可能决定了这种复杂结构的分裂。我的目的是创建视图来帮助"反规范化#34;将JSON转换为更传统的SQL数据格式以进行调试和过滤。
答案 0 :(得分:3)
查询显然会根据您的结构而改变,但我正在拿您的样本。
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_QUERY
或JSON_VALUE
,您可以走很长的路。如上所述,上述内容可以在视图中使用,因此Json的内容完全被隐藏了。
CROSS可以很容易地解决字符串变量的情况。将数据应用到我在上面的代码中显示的OPENJSON
函数。
这会让你更接近你需要的地方吗?