如何将存储过程中的宽结果集插入临时表或表变量?

时间:2016-04-05 11:55:19

标签: sql sql-server tsql stored-procedures sql-server-2012

我尝试使用我发现的各种方法将存储过程的输出保存到临时表或表变量中。

我已尝试声明临时表然后执行:

INSERT INTO #temptable EXEC storedprocedurename 

我遇到了一个问题,因为存储过程在结果集中有大约550列。我无法创建宽的临时表,因为最大行大小超过8060字节。

不幸的是,我没有能力编辑存储过程,但我只需要访问这些列中的大约200个。有没有办法只抓取我想要的列并将它们粘贴在表变量或临时表中以绕过大小问题或者我是否坚持将整行结果放在表中?

我也调查了OPENROWSET,但我使用的SQL服务器不允许启用ADHOC查询,也不会这样做。在这一点上我没有想法,因为我唯一知道要做的就是复制存储过程并删除大约1/2列我不需要的列,但这可能是一个维护如果源存储过程发生变化并且我不知道它就会出现问题。

3 个答案:

答案 0 :(得分:1)

我找不到在INSERT ... EXEC语句中只插入部分列的方法。这意味着临时表应该包含所有550列。但是,您可以尝试避免将所有返回的数据插入到这些列中。

第一个选项。 INSTEAD OF触发器。我从来没用过,所以我不确定它是否适用于临时表。它应该适用于普通表。主要思想 - 在触发器中拦截INSERT操作并替换超过8060字节限制的长值以及NULLs所不需要的值。

第二种选择。对于那些您不需要在varchar临时表语句中将varchar(1)定义为CREATE的长varchar列。主要思想 - 截断您不需要1个字符的长String or binary data would be truncated.个值,希望最后一行小于8060个字节。如果您尝试这种方法,您很可能会看到以下错误消息:SET ansi_warnings OFF要取消此错误消息并强制服务器截断数据:https?\:\/{2}[\w\.]+(\/[\w]+)+\-booker(\/[\w]+|\.[\w]+)

答案 1 :(得分:1)

你试过OPENQUERY吗?我认为它与OPENROWSET具有相同的要求。你会创建一个" loopback"链接服务器并在OPENQUERY的调用中使用它。但OPENQUERY有一些限制,因为它不喜欢动态SQL或其他任何限制sp_describe_first_result_set的内容。

EXEC sp_addlinkedserver
   @server = N'Loopback',
   @srvproduct = N'',
   @provider = N'SQLNCLI',
   @datasrc = N'<your server name>';

然后尝试:

SELECT * FROM OPENQUERY(Loopback, N'EXEC sp_who2'); -- this gets an error

SELECT * FROM OPENQUERY(Loopback, N'EXEC sp_who'); -- this works

如果OPENQUERY不是一个选项,那么通过SQLCLR仍然可以毫无困难地完成。您有两个主要选择:

  1. SQLCLR存储过程:这是一种更简单的方法,因为没有与现有存储过程正在执行的操作相关的限制(即动态SQL,副作用函数,DML,{{ 1}}语句等)。您可以使用内部上下文连接(即附加到您已经在的同一会话中,当程序集标记为SET时这可以工作),执行存储过程,并使用{{循环结果1}},在使用SAFE时将每一行发送回调用者(即将行流回来)。您将使用SqlDataReader创建结果集结构,并仅创建所需的列。然后,您可以从SqlDataReader中设置每个列,并且SqlDataReader有许多从未访问过的列,这无关紧要。

  2. SQLCLR表值函数:此方法的优点是实际上可以对操作发出SqlContext.Pipe.SendResultsRow,以便您可以添加SqlDataRecord条件等。您仍然可以使用SELECT / WHERE,就像使用SQLCLR存储过程一样。但是,有一些限制,就像有T-SQL函数一样。

    • 如果您当前的存储过程没有违反创建T-SQL函数的任何规则(即动态SQL,副作用函数,DML,SqlCommand语句等),那么您可以执行以下操作:在使用内部上下文连接时,只能从SQLCLR函数执行存储过程(即附加到您已经在的同一个会话中,这在程序集标记为SqlDataReader时有效)。但是,您无法将行流回来,而是需要将它们存储在内存中(类似于在T-SQL多语句TVF中使用表变量)并在结束时释放结果这个过程。
    • 如果您当前的存储过程确实违反了这些规则(并且SET会违反,因为它是SAFE声明),那么您仍然可以执行此操作,但您需要使用常规/外部连接,因为Context Connection无法正常工作。此选项确实具有使用SET NOCOUNT ON;流回行的好处,但它也有两个缺点:不是同一会话的一部分(因此无法看到本地临时表格或SET),并要求将程序集标记为yield return(但要求将数据库设置为CONTEXT_INFO:您只需签名在程序集中,从该DLL /程序集在EXTERNAL_ACCESS中创建一个非对称密钥,从该非对称密钥创建一个登录,最后授予登录TRUSTWORTHY ON权限的权限。
  3. 看到你正在点击的SQL Server不允许master,如果DBA说由于&#34; security&#34;而无法启用SQLCLR。风险,那么请将他们的注意力转向我在SQL Server Central上撰写关于SQLCLR的系列文章:Stairway to SQLCLR(查看该网站上的内容需要免费注册)。在前四篇文章中,我通过几个例子展示了SQLCLR的确切安全性,特别是当程序集标记为EXTERNAL ACCESS ASSEMBLY时(涵盖上述3个选项中的2个)。

答案 2 :(得分:0)

您可以使用游标将数据发送到具有限制数量的cols的临时表,直到它到达结尾。这可能会影响性能。