如何执行SELECT*INTO[temp table]FROM[存储过程]?不是FROM[Table]并且没有定义[temp Table]?

选择BusinessLine中的所有数据到tmpBusLine工作正常。

select *
into tmpBusLine
from BusinessLine

我也在尝试同样的方法,但使用返回数据的存储过程并不完全相同。

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

输出消息:

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

我读过几个创建与输出存储过程结构相同的临时表的示例,这很好,但最好不要提供任何列。


当前回答

我正在使用以下模式和数据创建一个表。创建存储过程。现在我知道我的过程的结果是什么,所以我正在执行以下查询。创建表[dbo]。[tbl测试树]([Id][int]标识(1,1)不为空,[ParentId][int]NULL,[IsLeft][bit]NULL,[IsRight][bit]NULL,CONSTRAINT[PK_tblTestingTree]主键集群([Id]ASC)(PAD_INDEX=关闭,STATISTICS_NORECOMPUTE=关闭,IGNORE_DUP_KEY=关闭,ALLOW_ROW_LOCKS=打开,ALLOW_PAGE_LOCKS=开启)打开[主])在[主要]去设置IDENTITY_INSERT[dbo]。[tbl测试树]打开插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(1,NULL,NULL,空)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(2,1,1,NULL)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(3,1,NULL,1)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(4,2,1,NULL)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(5,2,NULL,1)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(6,3,1,NULL)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(7,3,NULL,1)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(8,4,1,NULL)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(9,4,NULL,1)插入[dbo]。[tblTestingTree]([Id],[ParentId],[IsLeft],[IsRight])值(10,5,1,NULL)设置IDENTITY_INSERT[dbo]。[tbl测试树]关闭值(10,5,1,NULL)设置IDENTITY_INSERT[dbo]。[tblTestingTree]打开创建过程GetDate像开始从tblTestingTree中选择Id、ParentId终止创建表tbltemp(id int,父ID int)插入tbltempexec获取日期从tbltemp中选择*;

其他回答

如果要在不首先声明临时表的情况下执行此操作,可以尝试创建用户定义函数而不是存储过程,并使该用户定义函数返回表。或者,如果要使用存储过程,请尝试以下操作:

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'

嗯,您确实需要创建一个临时表,但它不需要有正确的模式。。。。我创建了一个存储过程,它修改了现有的临时表,使其具有正确的数据类型和顺序(删除所有现有列,添加新列)所需的列:

GO
create procedure #TempTableForSP(@tableId int, @procedureId int)  
as   
begin  
    declare @tableName varchar(max) =  (select name  
                                        from tempdb.sys.tables 
                                        where object_id = @tableId
                                        );    
    declare @tsql nvarchar(max);    
    declare @tempId nvarchar(max) = newid();      
    set @tsql = '    
    declare @drop nvarchar(max) = (select  ''alter table tempdb.dbo.' + @tableName 
            +  ' drop column ''  + quotename(c.name) + '';''+ char(10)  
                                   from tempdb.sys.columns c   
                                   where c.object_id =  ' + 
                                         cast(@tableId as varchar(max)) + '  
                                   for xml path('''')  
                                  )    
    alter table tempdb.dbo.' + @tableName + ' add ' + QUOTENAME(@tempId) + ' int;
    exec sp_executeSQL @drop;    
    declare @add nvarchar(max) = (    
                                select ''alter table ' + @tableName 
                                      + ' add '' + name 
                                      + '' '' + system_type_name 
                           + case when d.is_nullable=1 then '' null '' else '''' end 
                                      + char(10)   
                              from sys.dm_exec_describe_first_result_set_for_object(' 
                               + cast(@procedureId as varchar(max)) + ', 0) d  
                                order by column_ordinal  
                                for xml path(''''))    

    execute sp_executeSQL  @add;    
    alter table '  + @tableName + ' drop column ' + quotename(@tempId) + '  ';      
    execute sp_executeSQL @tsql;  
end         
GO

create table #exampleTable (pk int);

declare @tableId int = object_Id('tempdb..#exampleTable')
declare @procedureId int = object_id('examplestoredProcedure')

exec #TempTableForSP @tableId, @procedureId;

insert into #exampleTable
exec examplestoredProcedure

请注意,如果sys.dm_exec_descript_first_result_set_for_object无法确定存储过程的结果(例如,如果它使用临时表),则这将不起作用。

我将执行以下操作

创建(将SP转换为)UDF(表值UDF)。从dbo.UDF_getBusinessLineHistory“2009年3月16日”中选择*到#tmpBusLine

这是对您的问题稍作修改的答案。如果可以放弃对用户定义函数使用存储过程,则可以使用内联表值用户定义函数。这本质上是一个存储过程(将采用参数),它将表作为结果集返回;因此将与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,但这不是OPENROWET函数的用途(摘自联机丛书):

包括所有连接信息访问远程数据所需的来自OLE DB数据源。这方法是访问表,并且是一个一次性临时连接方法和使用OLE访问远程数据数据库。更频繁的参考OLE DB数据源,使用链接服务器。

使用OPENROWSET可以完成任务,但在打开本地连接和编组数据时会产生一些额外的开销。它也可能不是所有情况下的选项,因为它需要临时查询权限,这会带来安全风险,因此可能不需要。此外,OPENROWSET方法将排除使用返回多个结果集的存储过程。在单个存储过程中包装多个内联表值用户定义函数可以实现这一点。

这可以在SQL Server 2014+中完成,前提是存储过程只返回一个表。如果有人能为多张桌子找到这样的方法,我很想知道。

DECLARE @storedProcname NVARCHAR(MAX) = ''
SET @storedProcname = 'myStoredProc'

DECLARE @strSQL AS VARCHAR(MAX) = 'CREATE TABLE myTableName '

SELECT @strSQL = @strSQL+STUFF((
SELECT ',' +name+' ' + system_type_name 
FROM sys.dm_exec_describe_first_result_set_for_object (OBJECT_ID(@storedProcname),0)
FOR XML PATH('')
),1,1,'(') + ')'

EXEC (@strSQL)

INSERT INTO myTableName

EXEC ('myStoredProc @param1=1, @param2=2')

SELECT * FROM myTableName

DROP TABLE myTableName

这将从系统表中提取返回表的定义,并使用它为您构建临时表。然后,您可以如前所述从存储过程填充它。

还有一些变体也适用于动态SQL。