OPENJSON不会将所有文档都选择到SQL表中

时间:2019-03-13 12:39:36

标签: sql json sql-server sql-server-2016 open-json

我一直试图将JSON文件的内容导出到SQL Server表中。但是,尽管JSON中存在多行,但是输出SQL表仅包含JSON中的第一行。我使用的代码如下:

DROP TABLE IF EXISTS testingtable;

DECLARE @json VARCHAR(MAX) = '{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }, 
                              { "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51564999999999, 42.377017 ], "pop" : 36963, "state" : "MA" }';
SELECT * INTO testingtable FROM OPENJSON(@json) WITH (_id int, city varchar(20), loc float(50), pop int, state varchar(5)
)

SELECT * FROM testingtable

获得的输出如下: Click to view

3 个答案:

答案 0 :(得分:0)

该字符串不是有效的JSON。 JSON文档中不能有两个根对象。格式正确的JSON字符串如下所示:

DECLARE @json VARCHAR(MAX) = '{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" },
                              { "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51564999999999, 42.377017 ], "pop" : 36963, "state" : "MA" }';

应该是

DECLARE @json VARCHAR(MAX) = '[{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" },
                               { "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51564999999999, 42.377017 ], "pop" : 36963, "state" : "MA" }
                              ]';

像OPENJSON一样,它解析第一个对象并在遇到无效文本后立即停止。

快速且肮脏的解决方法是添加缺少的方括号:

SELECT * FROM OPENJSON('[' + @json + ']') WITH (_id int, city varchar(20), loc float(50), pop int, state varchar(5))

我怀疑该字符串来自将单独的记录存储在单独的行中的日志或事件文件。这是无效的,也没有任何标准或规范(尽管有域名抢注者),但是许多高流量应用程序都在使用它,例如在日志文件或事件流中。

之所以这样做,是因为不需要构造或读取整个数组来获取记录。为每条记录添加新行容易。读取大型文件并进行并行处理也更加容易-只需逐行阅读文本并将其提供给工作人员。或将文件分成N个部分到最接近的换行符,并将各个部分送入不同的计算机。这就是Map-Reduce的工作方式。

这就是为什么添加方括号是一个肮脏的解决方案-您必须先从MB或GB大小的文件中读取整个文本,然后才能对其进行解析。那不是OPENJSON要做的。

正确的解决方案是使用另一种工具逐行读取文件,解析记录并将值插入目标表。

答案 1 :(得分:0)

如果您知道JSON文档将不包含任何内部换行符,则可以使用string_split拆分字符串。 OPENJSON不在乎前导空格或尾随,。这样一来,您可以避免添加[ ]个字符,而不必将其解析为一个大文档。

EG:

DROP TABLE IF EXISTS testingtable;

DECLARE @jsonFragment VARCHAR(MAX) = '{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }, 
                              { "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51564999999999, 42.377017 ], "pop" : 36963, "state" : "MA" }';

SELECT * 
INTO testingtable 
FROM  string_split(@jsonFragment,CHAR(10))  docs
cross apply 
(
  select *
  from openjson(docs.value)
  WITH (_id int, city varchar(20), loc float(50), pop int, state varchar(5))
) d

SELECT * FROM testingtable

类似于XML,您可以将这种格式称为“ JSON片段”。这是SQL Server中XML和JSON之间的另一个区别。对于XML,引擎很乐意解析和存储XML片段,但不支持JSON。

答案 2 :(得分:0)

例如,多行JSON文本括在方括号中;

[
    {first data set},
    {second data set}, .....
]

您可以在将数据传递到此查询时添加方括号,也可以将方括号添加到您的 @json 变量(例如'[' + @json + ']'

DECLARE @json VARCHAR(MAX) = '{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }, 
                              { "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51564999999999, 42.377017 ], "pop" : 36963, "state" : "MA" }';
SELECT * INTO testingtable FROM OPENJSON ('['+ @json + ']') WITH (_id int, city varchar(20), loc float(50), pop int, state varchar(5)
)

SELECT * FROM testingtable