将存储过程的结果插入临时表

断了今生、忘了曾经 提交于 2019-12-16 09:52:35

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

如何SELECT * INTO [temp table] FROM [stored procedure]进行SELECT * INTO [temp table] FROM [stored procedure] ? 不是FROM [Table] ,也没有定义[temp table]

BusinessLine Select所有数据到tmpBusLine可以正常工作。

select *
into tmpBusLine
from BusinessLine

我正在尝试相同的方法,但是使用返回数据的stored procedure并不完全相同。

select *
into tmpBusLine
from
exec getBusinessLineHistory '16 Mar 2009'

输出信息:

消息156,级别15,状态1,第2行关键字“ exec”附近的语法错误。

我已经阅读了几个创建与输出存储过程具有相同结构的临时表的示例,该示例工作正常,但是最好不要提供任何列。


#1楼

如果您存储的proc的结果表太复杂而无法手动键入“ create table”语句,并且您不能使用OPENQUERY或OPENROWSET,则可以使用sp_help为您生成列和数据类型的列表。 获得列列表后,只需对其进行格式化即可满足您的需求。

步骤1:在输出查询中添加“进入#temp”(例如,“从[...]中选择到#temp”)。

最简单的方法是直接在proc中编辑输出查询。 如果您无法更改存储的proc,则可以将内容复制到新的查询窗口中,然后在其中修改查询。

步骤2:在临时表上运行sp_help。 (例如“ exec tempdb..sp_help #temp”)

创建临时表后,在临时表上运行sp_help以获得列和数据类型(包括varchar字段的大小)的列表。

步骤3:将数据列和类型复制到创建表语句中

我有一个Excel工作表,可用于将sp_help的输出格式化为“ create table”语句。 您不需要任何花哨的东西,只需复制并粘贴到SQL编辑器中即可。 使用列名,大小和类型来构造“创建表#x [...]”或“声明@x表[...]”语句,可用于插入存储过程的结果。

步骤4:插入到新创建的表

现在,您将拥有与该线程中描述的其他解决方案类似的查询。

DECLARE @t TABLE 
(
   --these columns were copied from sp_help
   COL1 INT,
   COL2 INT   
)

INSERT INTO @t 
Exec spMyProc 

此技术还可用于将临时表( #temp )转换为表变量( @temp )。 尽管这可能不仅仅是自己编写create table语句,而是更多的步骤,但它可以防止大型进程中出现诸如打字错误和数据类型不匹配之类的手动错误。 与最初编写查询相比,调试输入错误可能要花费更多时间。


#2楼

您可以为此使用OPENROWSET 。 看一看。 我还包括了sp_configure代码,以启用临时分布式查询(如果尚未启用)。

CREATE PROC getBusinessLineHistory
AS
BEGIN
    SELECT * FROM sys.databases
END
GO

sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO

SELECT * INTO #MyTempTable FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC getBusinessLineHistory')

SELECT * FROM #MyTempTable

#3楼

这是对您的问题的稍作修改的答案。 如果可以放弃对用户定义的函数使用存储过程,则可以使用内联表值用户定义的函数。 本质上,这是一个存储过程(将带有参数),该存储过程返回一个表作为结果集。 因此可以很好地放置INTO语句。

这是一篇很好的快速文章以及其他用户定义的函数。 如果仍然需要存储过程,则可以用存储过程包装内联表值用户定义函数。 存储过程在调用内联表值用户定义函数中的select *时仅传递参数。

因此,例如,您将具有一个内联表值用户定义函数,以获取特定区域的客户列表:

CREATE FUNCTION CustomersByRegion 
(  
    @RegionID int  
)
RETURNS TABLE 
AS
RETURN 
  SELECT *
  FROM customers
  WHERE RegionID = @RegionID
GO

然后,您可以调用此函数以获取如下结果:

SELECT * FROM CustomersbyRegion(1)

或执行SELECT INTO:

SELECT * INTO CustList FROM CustomersbyRegion(1)

如果仍然需要存储过程,则将函数包装为:

CREATE PROCEDURE uspCustomersByRegion 
(  
    @regionID int  
)
AS
BEGIN
     SELECT * FROM CustomersbyRegion(@regionID);
END
GO

我认为这是获得所需结果的最“少精打采”的方法。 它使用了现有功能,而没有任何复杂性。 通过在存储过程中嵌套内联表值用户定义函数,您可以通过两种方式访问​​该功能。 加! 实际的SQL代码只有一个维护点。

已建议使用OPENROWSET,但这不是OPENROWSET函数打算用于的目的(摘自Online Books):

包括从OLE DB数据源访问远程数据所需的所有连接信息。 此方法是访问链接服务器中的表的替代方法,并且是使用OLE DB连接和访问远程数据的一次性临时方法。 要更频繁地引用OLE DB数据源,请改用链接服务器。

使用OPENROWSET可以完成工作,但会增加一些打开本地连接和编组数据的开销。 由于它需要临时查询权限,因此可能并非在所有情况下都是一个选择,这会带来安全风险,因此可能不希望使用。 同样,OPENROWSET方法将排除使用存储过程返回多个结果集的情况。 在单个存储过程中包装多个内联表值用户定义函数可以实现此目的。


#4楼

您的存储过程是否仅检索数据或也对其进行修改? 如果仅将其用于检索,则可以将存储过程转换为函数并使用公用表表达式(CTE),而不必声明它,如下所示:

with temp as (
    select * from dbo.fnFunctionName(10, 20)
)
select col1, col2 from temp

但是,无论需要从CTE检索什么,都应仅在一条语句中使用。 您不能with temp as ...并在几行SQL之后尝试使用它。 您可以在一条语句中包含多个CTE,以进行更复杂的查询。

例如,

with temp1020 as (
    select id from dbo.fnFunctionName(10, 20)
),
temp2030 as (
    select id from dbo.fnFunctionName(20, 30)
)
select * from temp1020 
where id not in (select id from temp2030)

#5楼

我发现将数组/数据表传递到存储过程中可能使您对如何解决问题有了另一种认识。

该链接建议使用Image类型参数传递到存储过程中。 然后在存储过程中,将图像转换为包含原始数据的表变量。

也许有一种方法可以与临时表一起使用。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!