如何执行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”。

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


当前回答

此存储过程执行以下任务:

CREATE PROCEDURE [dbo].[ExecIntoTable]
(
    @tableName          NVARCHAR(256),
    @storedProcWithParameters   NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE @driver         VARCHAR(10)
    DECLARE @connectionString   NVARCHAR(600)
    DECLARE @sql            NVARCHAR(MAX)
    DECLARE @rowsetSql      NVARCHAR(MAX)

    SET @driver = '''SQLNCLI'''

    SET @connectionString = 
        '''server=' + 
            CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256)) + 
            COALESCE('\' + CAST(SERVERPROPERTY('InstanceName') AS NVARCHAR(256)), '') + 
        ';trusted_connection=yes'''

    SET @rowsetSql = '''EXEC ' + REPLACE(@storedProcWithParameters, '''', '''''') + ''''

    SET @sql = '
SELECT
    *
INTO 
    ' + @tableName + ' 
FROM
    OPENROWSET(' + @driver + ',' + @connectionString + ',' + @rowsetSql + ')'

    EXEC (@sql)
END
GO

这是一个轻微的修改:将存储过程结果插入到表中,使其实际工作。

如果希望它与临时表一起工作,则需要使用##GLOBAL表,然后将其删除。

其他回答

在四处搜索之后,我找到了一种方法,可以在不使用OPENROWSET或OPENQUERY的情况下,使用存储过程结果定义的通用模式为任何存储过程动态创建临时表,特别是当您不是数据库管理员时。

Sql服务器有一个内置过程sp_describe_first_result_set,它可以为您提供任何过程结果集的模式。我根据这个过程的结果创建了一个模式表,并手动将所有字段设置为NULLABLE。

declare @procname varchar(100) = 'PROCEDURENAME' -- your procedure name
declare @param varchar(max) = '''2019-06-06''' -- your parameters 
declare @execstr nvarchar(max) = N'exec ' + @procname
declare @qry nvarchar(max)

-- Schema table to store the result from sp_describe_first_result_set.
create table #d
(is_hidden  bit  NULL, column_ordinal   int  NULL, name sysname NULL, is_nullable   bit  NULL, system_type_id   int  NULL, system_type_name nvarchar(256) NULL,
max_length  smallint  NULL, precision   tinyint  NULL,  scale   tinyint  NULL,  collation_name  sysname NULL, user_type_id  int NULL, user_type_database    sysname NULL,
user_type_schema    sysname NULL,user_type_name sysname NULL,assembly_qualified_type_name   nvarchar(4000),xml_collection_id    int NULL,xml_collection_database    sysname NULL,
xml_collection_schema   sysname NULL,xml_collection_name    sysname NULL,is_xml_document    bit  NULL,is_case_sensitive bit  NULL,is_fixed_length_clr_type  bit  NULL,
source_server   sysname NULL,source_database    sysname NULL,source_schema  sysname NULL,source_table   sysname NULL,source_column  sysname NULL,is_identity_column bit NULL,
is_part_of_unique_key   bit NULL,is_updateable  bit NULL,is_computed_column bit NULL,is_sparse_column_set   bit NULL,ordinal_in_order_by_list   smallint NULL,
order_by_list_length    smallint NULL,order_by_is_descending    smallint NULL,tds_type_id   int  NULL,tds_length    int  NULL,tds_collation_id  int NULL,
tds_collation_sort_id   tinyint NULL)


-- Get result set definition of your procedure
insert into #d
EXEC sp_describe_first_result_set @exestr, NULL, 0

-- Create a query to generate and populate a global temp table from above results
select 
@qry = 'Create table ##t(' +
stuff(  
    (select ',' + name + ' '+ system_type_name + ' NULL'
    from #d d For XML Path, TYPE)
    .value(N'.[1]', N'nvarchar(max)')
, 1,1,'')
+ ')

insert into ##t 
Exec '+@procname+' ' + @param

Exec sp_executesql @qry

-- Use below global temp table to query the data as you may
select * from ##t

-- **WARNING** Don't forget to drop the global temp table ##t.
--drop table ##t
drop table #d 

在Sql Server版本-Microsoft Sql Server 2016(RTM)-13.0.1601.5(版本17134:)上开发和测试

您可以调整正在使用的SQL server版本的模式(如果需要)。

我正在使用以下模式和数据创建一个表。创建存储过程。现在我知道我的过程的结果是什么,所以我正在执行以下查询。创建表[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中选择*;

Quassnoi让我大部分时间都在那里,但有一点缺失:

****我需要在存储过程中使用参数****

OPENQUERY不允许这种情况发生:

因此,我找到了一种工作系统的方法,而且不必使表定义如此严格,并在另一个存储过程中重新定义它(当然,也要抓住它可能中断的机会)!

是的,您可以通过以下方式动态创建从存储过程返回的表定义使用带有伪变量的OPENQUERY语句(只要NO RESULT SET返回与具有良好数据的数据集相同数量的字段和相同位置)。

一旦创建了表,就可以整天在临时表中使用exec存储过程。


注意(如上所述),您必须启用数据访问,

EXEC sp_serveroption 'MYSERVERNAME', 'DATA ACCESS', TRUE

代码:

declare @locCompanyId varchar(8)
declare @locDateOne datetime
declare @locDateTwo datetime

set @locDateOne = '2/11/2010'
set @locDateTwo = getdate()

--Build temporary table (based on bogus variable values)
--because we just want the table definition and
--since openquery does not allow variable definitions...
--I am going to use bogus variables to get the table defintion.

select * into #tempCoAttendanceRpt20100211
FROM OPENQUERY(DBASESERVER,
  'EXEC DATABASE.dbo.Proc_MyStoredProc 1,"2/1/2010","2/15/2010 3:00 pm"')

set @locCompanyId = '7753231'

insert into #tempCoAttendanceRpt20100211
EXEC DATABASE.dbo.Proc_MyStoredProc @locCompanyId,@locDateOne,@locDateTwo

set @locCompanyId = '9872231'

insert into #tempCoAttendanceRpt20100211
EXEC DATABASE.dbo.Proc_MyStoredProc @locCompanyId,@locDateOne,@locDateTwo

select * from #tempCoAttendanceRpt20100211
drop table #tempCoAttendanceRpt20100211

感谢最初提供的信息。。。是的,最后,当使用来自另一个存储过程或数据库,是的,您也可以使用参数。

搜索参考标记:

SQL 2005存储过程到临时表带有存储过程和变量的openquery 2005带变量的openquery将存储过程执行到临时表中

更新:这将不适用于临时表,因此我不得不求助于手动创建临时表。

Bummer注意:这将不适用于临时表,http://www.sommarskog.se/share_data.html#OPENQUERY

参考:下一步是定义LOCALSERVER。在示例中,它可能看起来像一个关键字,但实际上它只是一个名称。这是您的做法:

sp_addlinkedserver @server = 'LOCALSERVER',  @srvproduct = '',
                   @provider = 'SQLOLEDB', @datasrc = @@servername

要创建链接服务器,您必须具有ALTER ANY server权限,或者是任何固定服务器角色sysadmin或setupadmin的成员。

OPENQUERY打开与SQL Server的新连接。这有一些含义:

使用OPENQUERY调用的过程不能引用在当前连接中创建的临时表。

新连接有自己的默认数据库(使用sp_addlinkedserver定义,默认为master),因此所有对象规范都必须包含数据库名称。

如果您有一个打开的事务,并且在调用OPENQUERY时持有锁,则被调用的过程无法访问您锁定的内容。也就是说,如果你不小心,你会挡住自己。

连接不是免费的,因此会造成性能损失。

我遇到了同样的问题,这是我根据保罗的建议所做的。这里的主要部分是使用NEWID()来避免多个用户同时运行存储过程/脚本,这是全局临时表的难题。

DECLARE @sql varchar(max) = '', 
@tmp_global_table varchar(255) = '##global_tmp_' + CONVERT(varchar(36), NEWID())
SET @sql = @sql + 'select * into [' + @tmp_global_table + '] from YOURTABLE'
EXEC(@sql)

EXEC('SELECT * FROM [' + @tmp_global_table + ']')

此存储过程执行以下任务:

CREATE PROCEDURE [dbo].[ExecIntoTable]
(
    @tableName          NVARCHAR(256),
    @storedProcWithParameters   NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE @driver         VARCHAR(10)
    DECLARE @connectionString   NVARCHAR(600)
    DECLARE @sql            NVARCHAR(MAX)
    DECLARE @rowsetSql      NVARCHAR(MAX)

    SET @driver = '''SQLNCLI'''

    SET @connectionString = 
        '''server=' + 
            CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256)) + 
            COALESCE('\' + CAST(SERVERPROPERTY('InstanceName') AS NVARCHAR(256)), '') + 
        ';trusted_connection=yes'''

    SET @rowsetSql = '''EXEC ' + REPLACE(@storedProcWithParameters, '''', '''''') + ''''

    SET @sql = '
SELECT
    *
INTO 
    ' + @tableName + ' 
FROM
    OPENROWSET(' + @driver + ',' + @connectionString + ',' + @rowsetSql + ')'

    EXEC (@sql)
END
GO

这是一个轻微的修改:将存储过程结果插入到表中,使其实际工作。

如果希望它与临时表一起工作,则需要使用##GLOBAL表,然后将其删除。