8

我的开发 PC 上安装了 SQL Server 2012 完整版。

我正在尝试按照此处的示例进行操作,这些示例显示了如何使用存储过程作为数据源来创建新的临时表。我试图将几个存储过程的结果组合到一个临时表中(各种结果集的列结构/定义是相同的)。

为了测试管道是否正常工作,我发出以下查询:

 SELECT * FROM OPENQUERY("FOO\SQL2012", 'exec mySchema.myStoredProc')

但是我从那个简单的测试管道选择查询中得到了这个错误:

消息 11526,级别 16,状态 1,过程 sp_describe_first_result_set,第 1 行
无法确定元数据,因为语句 'insert #tmp(foo1, foo2, foo3) select 'O' as foo1, foo2, foo3' in procedure 'myStoredProc' 使用一个临时表。

如果我正确理解错误,OPENQUERY 取决于服务器能够从数据库中的持久定义中提取列数据类型,并且在我的存储过程中实例化的临时表是短暂的,缺少持久定义。如果是这种情况,是否有任何设置告诉 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
4

4 回答 4

13

尝试这个:

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 中,您还可以选择使用表值参数传递数据。

您可能想阅读 Erland Sommarskog 的如何在存储过程之间共享数据,因为它可能会为您提供实现目标的方法的灵感。

于 2013-01-13T02:12:26.173 回答
4

WITH RESULT SETS [NONE | UNDEFINED]在 EXEC 调用的末尾添加“ ”应该可以解决这个问题。http://technet.microsoft.com/en-us/library/ms188332.aspx

于 2013-11-29T15:47:41.997 回答
2

如果远程过程返回一个结果集,则必须以 启动该过程SET NOCOUNT ON,否则第一个结果集是没有任何元数据的行数,并且总是会生成错误。

WITH RESULT SETS((field1 type1, field2 type2...))然后可以在 EXEC 语句的末尾使用定义结果集。

(这并没有直接回答问题,但我遇到了同样的错误,因为我的存储过程创建了一个临时表来存储中间结果。)

于 2020-09-03T15:18:01.127 回答
1

如果来宾服务器 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
于 2015-01-15T15:59:29.753 回答