我的开发PC上安装了SQL Server 2012完整版。
我试图遵循示例here,它们展示了如何使用存储过程作为数据源创建新的临时表。我试图将几个存储过程的结果合并到一个临时表中(各种结果集的列结构/定义是相同的)。
为了测试管道是否正常工作,我发出以下查询:
SELECT * FROM OPENQUERY("FOO\SQL2012", 'exec mySchema.myStoredProc')
但是我从这个简单的测试管道选择查询中得到了这个错误:
Msg 11526,Level 16,State 1,Procedure sp_describe_first_result_set,Line 1 无法确定元数据,因为语句'insert #tmp(foo1,foo2,foo3) 在过程'myStoredProc'中选择'O'作为foo1,foo2,foo3'使用临时表。
如果我正确理解错误,OPENQUERY依赖于服务器能够从数据库中的 persistent 定义中提取列数据类型,并且在我的存储过程中实例化的临时表是短暂的,缺乏持久的定义。如果是这种情况,是否有任何设置告诉OPENQUERY尽其所能并尝试对列数据类型进行智能猜测?
这是我正在测试的虚拟SP:
create proc testproc
as
begin
create table #test
(id int, name varchar(5) );
insert into #test(id,name)values(1,'xxx');
select * from #test;
--drop table #test; -- tried dropping and not dropping, same error either way
end
答案 0 :(得分:11)
试试这个:
SELECT *
FROM OPENQUERY("FOO\SQL2012", 'SET FMTONLY OFF; EXEC mySchema.myStoredProc;') X;
这样做的原因是,当您跨链接服务器执行存储过程时,提供程序首先尝试确定生成的行集的形状。它通过发出SET FMTONLY ON;
然后运行您的语句来完成此操作。在不使用临时表的存储过程中,这非常有效。查询解析器基本上执行干运行而不实际获取所有数据,只是元数据(有点像显示估计的执行计划)。
问题是,当存储过程 使用临时表时,它会失败,因为临时表的元数据不存在:无法通过适用于其的元分析收集它不使用临时表的存储过程。然后,解决方法是在执行存储过程的批处理中手动SET FMTONLY OFF;
。
请注意,使用此方法会使存储过程运行两次。第一次收集元数据(被丢弃的数据),第二次实际返回数据。如果被叫存储过程特别昂贵或有副作用,您可能需要考虑。
最后,请注意,此技巧不适用于每个存储过程。存储过程可以做的事情只是在工作中抛出一把扳手。我不知道所有的可能性,但其中一个是返回多个记录集。
响应您的更新SET FMTONLY OFF
不起作用:您是否可以重构SP以不使用临时表,或使用会话密钥永久表?这些选项中的任何一个都可以完成这项工作。在SQL Server 2012中,您还可以选择使用table-valued parameters传递数据。
您可能希望阅读Erland Sommarskog的How to Share Data between Stored Procedures,因为它可能为您提供实现目标的灵感。
答案 1 :(得分:3)
在EXEC调用结束时添加“WITH RESULT SETS [NONE | UNDEFINED]
”应该可以解决此问题。 http://technet.microsoft.com/en-us/library/ms188332.aspx
答案 2 :(得分:1)
如果guest虚拟机服务器sp在开头没有结果集(选择查询),则链接服务器无法解析结果集。 我使用的选项如下:
create procedure test
as
if 1=2
select a, b, c from table
declare @variable varchar(10)
----...and rest of your procedure...
--in the end
select a, b, c from table
答案 3 :(得分:0)
如果远程过程返回一个结果集,则必须使用SET NOCOUNT ON
启动该过程,否则第一个结果集是没有任何元数据的行数,并且总是会产生错误。
然后,可以在EXEC语句的末尾使用WITH RESULT SETS((field1 type1, field2 type2...))
定义结果集。
(这不能直接回答问题,但是我有同样的错误,因为我的存储过程创建了一个临时表来存储中间结果。)