SSMS:OPENJSON 有效,但不适用于直接 REST 调用
Posted
技术标签:
【中文标题】SSMS:OPENJSON 有效,但不适用于直接 REST 调用【英文标题】:SSMS: OPENJSON works but not with direct REST call 【发布时间】:2018-10-04 11:39:44 【问题描述】:在this article 之后,我正在尝试实现一个查询,该查询可以从 REST 调用中检索数据并使用 OPENJSON 解析 JSON。
我用 Postman 打电话给this URL 检查数据是否正常:
数据在那里。
我复制粘贴 JSON 并在 SSMS 上测试我的调用:
DECLARE @json nvarchar(max) = N'
"version": 0.6,
"generator": "Overpass API 0.7.55.4 3079d8ea",
"osm3s":
"timestamp_osm_base": "2018-10-04T10:07:02Z",
"timestamp_areas_base": "2018-10-04T09:02:02Z",
"copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."
,
"elements": [
"type": "node",
"id": 501591237,
"lat": 49.4943882,
"lon": -117.2910343,
"tags":
"amenity": "cinema",
"name": "Civic Theatre",
"website": "http://civictheatre.ca"
,
"type": "node",
"id": 2293276829,
"lat": -41.2709865,
"lon": 173.2842196,
"tags":
"amenity": "cinema",
"name": "Cinema 6"
]
';
SELECT * FROM OPENJSON(@json, N'$.elements')
WITH (
[type] nvarchar(max) N'$.type' ,
[id] nvarchar(max) N'$.id',
[lat] nvarchar(max) N'$.lat',
[lon] nvarchar(max) N'$.lon',
[amenity] nvarchar(max) N'$.tags.amenity',
[name] nvarchar(max) N'$.tags.name'
)
一切正常,工作正常:我的查询可以解析 JSON。
我现在关注this guide,它向我展示了如何在 SSMS 中进行 REST 调用,我尝试检索相同 URL 的数据并在 SSMS 中即时查看它们:
Declare @Object as Int;
Declare @json as nvarchar(max);
Exec sp_OACreate 'MSXML2.XMLHTTP', @Object OUT;
Exec sp_OAMethod @Object, 'open', NULL, 'get',
'http://overpass-api.de/api/interpreter?data=[out:json];area[name=%22Nelson%22]-%3E.a;(node(area.a)[amenity=cinema];way(area.a)[amenity=cinema];rel(area.a)[amenity=cinema];);out;', --Your Web Service Url (invoked)
'false'
Exec sp_OAMethod @Object, 'send'
Exec sp_OAMethod @Object, 'responseText', @json OUTPUT
select @json
SELECT * FROM OPENJSON(@json, N'$.elements')
WITH (
[type] nvarchar(max) N'$.type' ,
[id] nvarchar(max) N'$.id',
[lat] nvarchar(max) N'$.lat',
[lon] nvarchar(max) N'$.lon',
[amenity] nvarchar(max) N'$.tags.amenity',
[name] nvarchar(max) N'$.tags.name'
)
Exec sp_OADestroy @Object
哎哟!不工作!
为什么数据是空的? Declare @json as nvarchar(max);
在上一个查询中工作。为什么不再工作了?
如果我输入 Declare @json as varchar(8000);
它只是因为我检索不到 8000 个字符但我不能以这种方式工作。
如果我没记错的话,OPENJSON
正是为了避免此类问题而开发的,并加载到 2GB 的数据。
我想使用nvarchar(max)
并加载大量数据。这就是使用OPENJSON
的重点。
【问题讨论】:
SSMS 是客户端工具,与查询无关。 OPENJSON 与其输入的生成方式无关。而sp_OAMethod
不是进行 HTTP 调用的好方法。除了创建孤立对象的风险之外,它不能传递标头或处理响应。它在之前 SQL Server 2005 中使用。如果您必须进行HTTP 调用,至少使用SQLCLR。更好的是,从客户端而不是数据库进行调用
顺便说一句,输出意味着该 HTTP 调用没有返回任何内容,而不是 OPENJSON 失败。如果 HTTP 调用失败,服务器会返回状态码和说明,说明问题所在,例如 401 未授权、404 未找到等。在这些情况下没有响应文本
您需要检索status 属性,例如使用sp_OAMethod @Object, 'status'
和statusText 来查看调用失败的原因。
@PanagiotisKanavos,您可以发布 body
和 headers
。不幸的是,我不能在客户机器上删除 DLL。我知道是错的,但是 sp_OAMethod 可以在几秒钟内完成工作,这是我唯一可以使用的方法
如前所述,如果我用varchar(8000)
替换nvarchar(max)
,我会在SSMS 中看到JSON。谢谢你的提示,我使用了sp_OAMethod @Object, 'status'
,是的,我有一个 200。所以这个电话很好。 varchar(8000)
可以容纳 JSON,因为可以容纳 8000 个字符,但 nvarchar(MAX)
只能容纳 4000 个字符。
【参考方案1】:
完成。
非常感谢@PanagiotisKanavos 提出的status
的建议,以便发现错误。
解决方案是使用 Declare @json as table(Json_Table nvarchar(max))
并将 JSON 存储到表中而不是变量中。 现在可以存储 2GB!!!
Declare @Object as Int;
DECLARE @hr int
Declare @json as table(Json_Table nvarchar(max))
Exec @hr=sp_OACreate 'MSXML2.ServerXMLHTTP.6.0', @Object OUT;
IF @hr <> 0 EXEC sp_OAGetErrorInfo @Object
Exec @hr=sp_OAMethod @Object, 'open', NULL, 'get',
'http://overpass-api.de/api/interpreter?data=[out:json];area[name="Auckland"]->.a;(node(area.a)[amenity=cinema];way(area.a)[amenity=cinema];rel(area.a)[amenity=cinema];);out;', --Your Web Service Url (invoked)
'false'
IF @hr <> 0 EXEC sp_OAGetErrorInfo @Object
Exec @hr=sp_OAMethod @Object, 'send'
IF @hr <> 0 EXEC sp_OAGetErrorInfo @Object
Exec @hr=sp_OAMethod @Object, 'responseText', @json OUTPUT
IF @hr <> 0 EXEC sp_OAGetErrorInfo @Object
INSERT into @json (Json_Table) exec sp_OAGetProperty @Object, 'responseText'
SELECT * FROM OPENJSON((select * from @json), N'$.elements')
WITH (
[type] nvarchar(max) N'$.type' ,
[id] nvarchar(max) N'$.id',
[lat] nvarchar(max) N'$.lat',
[lon] nvarchar(max) N'$.lon',
[amenity] nvarchar(max) N'$.tags.amenity',
[name] nvarchar(max) N'$.tags.name'
)
EXEC sp_OADestroy @Object
这是完成工作的正确方法吗?
不!我不应该使用sp_OAMethod
,而应该使用SQLCLR
,或者用Python
、PowerShell
、VB
、C#
等编写的任何其他外部进程...
但是,你知道,我也应该少喝啤酒,少买培根,但是……YOLO,不管行得通……就去做吧。
多亏了这一点,我现在可以创建一个存储过程来进行 REST 调用并自动将数据保存到 SQL Server 中。我找了几天的解决方案,终于找到了答案here。
我希望这会有所帮助,我看到有几百人在搜索此回复。
【讨论】:
以上是关于SSMS:OPENJSON 有效,但不适用于直接 REST 调用的主要内容,如果未能解决你的问题,请参考以下文章
为啥后缀增量不适用于 void *ptr,但 ptr = ptr + 1 有效?
使用邮递员的 GET 请求有效,但不适用于 python (HTTPSConnectionPool)
基于日期范围查找文档在 mongodb shell 中有效,但不适用于 pymongo