当SP包含#temp表时,使用OPENROWSET动态检索SP结果

Zok*_*otz 10 sql t-sql sql-server dynamic-sql openrowset

我的情景

我正在开发一个数据库,该数据库将包含整个服务器上不同数据库中各种存储过程的许多详细信息.我现在试图收集的信息是"SP输出什么?"

在搜索中我发现答案在于OPENROWSET.我的初步测试成功,一切看起来都很棒.但是,在使用实时SP进行测试后,我遇到了一个主要问题:它与temp(#)表不兼容.

例如:

如果我要拿这个SP:

CREATE PROCEDURE dbo.zzTempSP(@A INT, @B INT) AS
SELECT @A AS A, @B AS B
Run Code Online (Sandbox Code Playgroud)

我可以使用以下代码轻松地将输出插入到临时(##)表中,然后查询tempdb的sysobjects并生成列及其数据类型的列表:

IF OBJECT_ID('tempdb.dbo.##TempOutput','U') IS NOT NULL DROP TABLE ##TempOutput

DECLARE @sql VARCHAR(MAX)
SELECT @sql = 'SELECT * 
               INTO ##TempOutput
               FROM OPENROWSET(''SQLNCLI'', ''Server=' + 
        CONVERT(VARCHAR(100), SERVERPROPERTY('MachineName')) +
                             ';Trusted_Connection=yes;'', ''SET FMTONLY OFF exec ' + 
                               DB_NAME() + 
                              '.dbo.zzTempSP @A=1, @B=2'')'
EXEC(@sql)

SELECT *
FROM ##TempOutput
Run Code Online (Sandbox Code Playgroud)

大!但是,如果SP是这样的:

CREATE PROCEDURE dbo.zzTempSP (@A INT, @B INT) AS CREATE TABLE dbo.#T (A INT, B INT)

INSERT INTO dbo.#T
SELECT   @A AS A, @B AS B

SELECT *
FROM dbo.#T
Run Code Online (Sandbox Code Playgroud)

当我执行与OPENROWSET以前相同的代码时,我收到以下错误:

无法处理对象"SET FMTONLY OFF exec DatabaseName.dbo.zzTempSP @ A = 1,@ B = 2".链接服务器"(null)"的OLE DB提供程序"SQLNCLI10"表示该对象没有列,或者当前用户没有该对象的权限.

当我减少OPENROWSET代码(通过删除动态的东西)到这个:

SELECT   *
FROM OPENROWSET('SQLNCLI','Server=ServerName;Trusted_Connection=yes;',
                          'exec DatabaseName.dbo.zzTempSP @A=1,@B=2'
              )
Run Code Online (Sandbox Code Playgroud)

我收到以下(更有用)错误:

无效的对象名称'#T'.

这就是我撞墙的地方.在我的搜索中似乎没有解决方案,但我还是不能让自己放弃它.

所以我被引导到......

我向你提问

是否有人知道任何可能的方法来规避这个错误?或者是否有可能的替代解决方案?

这个过程不会经常运行,所以我不必过分担心解决方案的效率.

任何投入将不胜感激.

谢谢,Zok

PS:抱歉格式化.我没有弄清楚语言标签.

Zok*_*otz 18

我也在SQL Server Central上发布了这个问题,一些回复让我回过头来寻找OPENROWSET中的答案(并找到它).其中一个人把我转到了本文关于OPENQUERY的部分.它声明,为了解决临时表的问题,您只需将SET FMTONLY OFF添加到OPENQUERY/OPENROWSET语句的执行行,如下所示:

SELECT  *
FROM    OPENROWSET( 'SQLNCLI',
                    'Server=SERVERNAME;Trusted_Connection=yes;',
                    'SET FMTONLY OFF; exec DatabaseName.dbo.zzTempSP @A=1,@B=2'
                  )
Run Code Online (Sandbox Code Playgroud)

但是,如果该过程未指定SET NOCOUNT ON,则仍会引发错误.我对自己脑后的SET NOCOUNT ON有一种愚蠢的误解,这让我无法思考,"嘿,我不能把SET NOCOUNT ON添加到OPENROWSET的执行语句中吗?" 一旦有人在另一个线程上向我提出这个问题,那就太有道理了=)所以,这是我一直在寻找的解决方案:

SELECT  *
FROM    OPENROWSET( 'SQLNCLI',
                    'Server=SERVERNAME;Trusted_Connection=yes;',
                    'SET FMTONLY OFF; SET NOCOUNT ON; exec DatabaseName.dbo.zzTempSP @A=1,@B=2'
                  )
Run Code Online (Sandbox Code Playgroud)