SQL Server 2016 存储过程运行
SQL Server 2016 stored procedure to function
我创建了一个存储过程,它使用临时 table 获取 Bing 映射 XML 的大量结果并将其转换为 varchar
,以便我可以用它来检索多个字段。将其转换为 varchar
的原因是 XML 对于 sp_OAMethod
来说太大了,而我的变量总是空白。
set @serviceUrl = 'https://dev.virtualearth.net/REST/v1/Routes/Truck?wp.0=' + @ToAddress + '&wp.1=' + @FromAddress + '&vehicleHazardousMaterials=Flammable&output=xml&key=XXX-000-XXX'
Exec sp_OACreate 'MSXML2.XMLHTTP', @Object OUT;
Exec sp_OAMethod @Object, 'open', NULL, 'get',@serviceUrl, 'false'
Exec sp_OAMethod @Object, 'send'
Exec sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT
exec @returnCode = sp_oamethod @Object, 'read', @ResponseText out, -1
Create table #tmp(dt xml)
insert into #tmp
exec @hr = sp_OAGetProperty @Object, 'responseXML.XML'
Set @ResponseText = Convert(varchar(max), (SELECT dt from #tmp))
Drop Table #tmp
select REPLACE(SUBSTRING(@ResponseText,PATINDEX('%<TravelDistance>%',@ResponseText),21),'<TravelDistance>','') Miles
,REPLACE(REPLACE(SUBSTRING(@ResponseText,PATINDEX('%<TravelDuration>%',@ResponseText),21),'<TravelDuration>',''),'<','')/60 TravelMinutes
以上不是完整代码;我对它进行了严格的编辑以使其更易于阅读。
我敢肯定有更好的方法来做到这一点,但这很有效,而且非常令人兴奋。
但是,计划是创建一个可以与其他临时查询一起使用以检索相同数据的函数。由于临时 table 或从函数内部填充 table,因此不可能作为函数。
那么有没有人有办法使这成为可能?
你真的应该为此使用 CLR。此处距离正确的存储过程还有很长的路要走,最好避免使用 sp_OAxxx 过程。您没有正确处理 return 代码,您使用了错误的 HTTP 组件,并且没有使用 SQL 服务器的 XML 解析器解析结果。最初看起来 CLR 实现可能需要更多工作,但维护使用 sp_OAxxx 存储过程和 COM 互操作的代码总是很痛苦。
很少有人了解这段代码是如何工作的,如何修改它,是否安全可靠。下一个拥有你的代码库的人可能不是这些人中的一员。在你的项目中有这样的代码是不好的。
如果您确实使用 CLR,您仍然不应该使用函数(尽管从技术上讲可以)。您不应在查询中间执行任何外部访问。
无论如何,这是对您现有方法的一些修正:
declare @serviceURL varchar(max)
declare @returnCode int
declare @errorMessage nvarchar(max)
declare @Object int
declare @hr int
declare @key varchar(2000) = 'Aoj...nFS'
declare @FromAddress nvarchar(max) = '7000 N SH 161, Irving TX 75039'
declare @ToAddress nvarchar(max) = '8617 Garland Rd, Dallas, TX 75218'
set @serviceUrl = 'https://dev.virtualearth.net/REST/v1/Routes/Truck?wp.0=' + @ToAddress + '&wp.1=' + @FromAddress + '&vehicleHazardousMaterials=Flammable&output=xml&key=' + @key
exec @hr = sp_OACreate 'MSXML2.ServerXMLHTTP', @Object OUT;
IF @hr <> 0
begin
set @errorMessage = concat('sp_OACreate failed ', convert(varchar(20),cast(@hr as varbinary(4)),1));
throw 60000, @errorMessage, 1;
end;
begin try
Exec @hr = sp_OAMethod @Object, 'open', NULL, 'get',@serviceUrl, 'false'
IF @hr <> 0
begin
set @errorMessage = concat('open failed ', convert(varchar(20),cast(@hr as varbinary(4)),1));
throw 60000, @errorMessage, 1;
end;
Exec @hr = sp_OAMethod @Object, 'send'
IF @hr <> 0
begin
set @errorMessage = concat('send failed ', convert(varchar(20),cast(@hr as varbinary(4)),1));
throw 60000, @errorMessage, 1;
end;
declare @responseCode int;
Exec @hr = sp_OAGetProperty @Object, 'status', @responseCode out
IF @hr <> 0 or @responseCode <> 200
begin
set @errorMessage = concat('send failed hr:', convert(varchar(20),cast(@hr as varbinary(4)),1),' http response code: ', @responseCode);
throw 60000, @errorMessage, 1;
end;
declare @tmp table(doc xml)
insert into @tmp
exec @hr = sp_OAGetProperty @Object, 'ResponseXML.XML'
IF @hr <> 0
begin
set @errorMessage = concat('ResponseXML.XML failed ', convert(varchar(20),cast(@hr as varbinary(4)),1));
throw 60000, @errorMessage, 1;
end;
WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/search/local/ws/rest/v1')
select doc.value('(//TravelDistance)[1]', 'float') TravelDistance,
doc.value('(//DistanceUnit)[1]', 'nvarchar(20)') DistanceUnit,
doc.value('(//TravelDuration)[1]', 'float') TravelDuration,
doc.value('(//DurationUnit)[1]', 'nvarchar(20)') DurationUnit
from @tmp;
end try
begin catch
exec @hr = sp_OADestroy @Object ;
throw;
end catch
我创建了一个存储过程,它使用临时 table 获取 Bing 映射 XML 的大量结果并将其转换为 varchar
,以便我可以用它来检索多个字段。将其转换为 varchar
的原因是 XML 对于 sp_OAMethod
来说太大了,而我的变量总是空白。
set @serviceUrl = 'https://dev.virtualearth.net/REST/v1/Routes/Truck?wp.0=' + @ToAddress + '&wp.1=' + @FromAddress + '&vehicleHazardousMaterials=Flammable&output=xml&key=XXX-000-XXX'
Exec sp_OACreate 'MSXML2.XMLHTTP', @Object OUT;
Exec sp_OAMethod @Object, 'open', NULL, 'get',@serviceUrl, 'false'
Exec sp_OAMethod @Object, 'send'
Exec sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT
exec @returnCode = sp_oamethod @Object, 'read', @ResponseText out, -1
Create table #tmp(dt xml)
insert into #tmp
exec @hr = sp_OAGetProperty @Object, 'responseXML.XML'
Set @ResponseText = Convert(varchar(max), (SELECT dt from #tmp))
Drop Table #tmp
select REPLACE(SUBSTRING(@ResponseText,PATINDEX('%<TravelDistance>%',@ResponseText),21),'<TravelDistance>','') Miles
,REPLACE(REPLACE(SUBSTRING(@ResponseText,PATINDEX('%<TravelDuration>%',@ResponseText),21),'<TravelDuration>',''),'<','')/60 TravelMinutes
以上不是完整代码;我对它进行了严格的编辑以使其更易于阅读。
我敢肯定有更好的方法来做到这一点,但这很有效,而且非常令人兴奋。
但是,计划是创建一个可以与其他临时查询一起使用以检索相同数据的函数。由于临时 table 或从函数内部填充 table,因此不可能作为函数。
那么有没有人有办法使这成为可能?
你真的应该为此使用 CLR。此处距离正确的存储过程还有很长的路要走,最好避免使用 sp_OAxxx 过程。您没有正确处理 return 代码,您使用了错误的 HTTP 组件,并且没有使用 SQL 服务器的 XML 解析器解析结果。最初看起来 CLR 实现可能需要更多工作,但维护使用 sp_OAxxx 存储过程和 COM 互操作的代码总是很痛苦。
很少有人了解这段代码是如何工作的,如何修改它,是否安全可靠。下一个拥有你的代码库的人可能不是这些人中的一员。在你的项目中有这样的代码是不好的。
如果您确实使用 CLR,您仍然不应该使用函数(尽管从技术上讲可以)。您不应在查询中间执行任何外部访问。
无论如何,这是对您现有方法的一些修正:
declare @serviceURL varchar(max)
declare @returnCode int
declare @errorMessage nvarchar(max)
declare @Object int
declare @hr int
declare @key varchar(2000) = 'Aoj...nFS'
declare @FromAddress nvarchar(max) = '7000 N SH 161, Irving TX 75039'
declare @ToAddress nvarchar(max) = '8617 Garland Rd, Dallas, TX 75218'
set @serviceUrl = 'https://dev.virtualearth.net/REST/v1/Routes/Truck?wp.0=' + @ToAddress + '&wp.1=' + @FromAddress + '&vehicleHazardousMaterials=Flammable&output=xml&key=' + @key
exec @hr = sp_OACreate 'MSXML2.ServerXMLHTTP', @Object OUT;
IF @hr <> 0
begin
set @errorMessage = concat('sp_OACreate failed ', convert(varchar(20),cast(@hr as varbinary(4)),1));
throw 60000, @errorMessage, 1;
end;
begin try
Exec @hr = sp_OAMethod @Object, 'open', NULL, 'get',@serviceUrl, 'false'
IF @hr <> 0
begin
set @errorMessage = concat('open failed ', convert(varchar(20),cast(@hr as varbinary(4)),1));
throw 60000, @errorMessage, 1;
end;
Exec @hr = sp_OAMethod @Object, 'send'
IF @hr <> 0
begin
set @errorMessage = concat('send failed ', convert(varchar(20),cast(@hr as varbinary(4)),1));
throw 60000, @errorMessage, 1;
end;
declare @responseCode int;
Exec @hr = sp_OAGetProperty @Object, 'status', @responseCode out
IF @hr <> 0 or @responseCode <> 200
begin
set @errorMessage = concat('send failed hr:', convert(varchar(20),cast(@hr as varbinary(4)),1),' http response code: ', @responseCode);
throw 60000, @errorMessage, 1;
end;
declare @tmp table(doc xml)
insert into @tmp
exec @hr = sp_OAGetProperty @Object, 'ResponseXML.XML'
IF @hr <> 0
begin
set @errorMessage = concat('ResponseXML.XML failed ', convert(varchar(20),cast(@hr as varbinary(4)),1));
throw 60000, @errorMessage, 1;
end;
WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/search/local/ws/rest/v1')
select doc.value('(//TravelDistance)[1]', 'float') TravelDistance,
doc.value('(//DistanceUnit)[1]', 'nvarchar(20)') DistanceUnit,
doc.value('(//TravelDuration)[1]', 'float') TravelDuration,
doc.value('(//DurationUnit)[1]', 'nvarchar(20)') DurationUnit
from @tmp;
end try
begin catch
exec @hr = sp_OADestroy @Object ;
throw;
end catch