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

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


当前回答

如果存储过程的结果表太复杂,无法手动键入“createtable”语句,并且不能使用OPENQUERY或OPENROWSET,则可以使用sp_help为您生成列和数据类型列表。一旦您有了列列表,就只需要将其格式化以满足您的需要。

步骤1:将“into#temp”添加到输出查询中(例如“select[…]into#TEMPfrom[…]”)。

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

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

创建临时表后,对临时表运行sp_help以获取列和数据类型的列表,包括varchar字段的大小。

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

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

步骤4:插入新创建的表

现在,您将得到一个与本主题中描述的其他解决方案类似的查询。

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

INSERT INTO @t 
Exec spMyProc 

此技术也可用于将临时表(#temp)转换为表变量(@temp)。虽然这可能比自己编写createtable语句要简单得多,但它可以防止大型进程中出现诸如拼写错误和数据类型不匹配等手动错误。调试拼写错误可能比一开始编写查询要花费更多的时间。

其他回答

首先,修改存储过程以将最终结果保存到临时表中。通过这样做,我们将创建一个与SP输出字段匹配的表。然后使用select语句将该临时表保存为任意表名。然后按照步骤2中的说明执行SP

步骤1:修改存储过程以将最终结果保存到临时表中

[your stored procedure] 

into #table_temp //this will insert the data to a temp table

from  #table_temp 

select * into SP_Output_Table_1 from #table_temp //this will save data to a actual table

步骤2:按如下所示执行SP,将记录插入到表中

Insert SP_Output_Table_1
EXE  You_SP_Nane @Parameter1 = 52, @parameter2 =1

Code

CREATE TABLE #T1
(
    col1 INT NOT NULL,
    col2 NCHAR(50) NOT NULL,
    col3 TEXT NOT NULL,
    col4 DATETIME NULL,
    col5 NCHAR(50) NULL,
    col6 CHAR(2) NULL,
    col6 NCHAR(100) NULL,
    col7 INT NULL,
    col8 NCHAR(50) NULL,
    col9 DATETIME NULL,
    col10 DATETIME NULL
)

DECLARE @Para1 int
DECLARE @Para2 varchar(32)
DECLARE @Para3 varchar(100)
DECLARE @Para4 varchar(15)
DECLARE @Para5 varchar (12)
DECLARE @Para6 varchar(1)
DECLARE @Para7 varchar(1)


SET @Para1 = 1025
SET @Para2 = N'6as54fsd56f46sd4f65sd'
SET @Para3 = N'XXXX\UserName'
SET @Para4 = N'127.0.0.1'
SET @Para5 = N'XXXXXXX'
SET @Para6 = N'X'
SET @Para7 = N'X'

INSERT INTO #T1
(
    col1,
    col2,
    col3,
    col4,
    col5,
    col6,
    col6,
    col7,
    col8,
    col9,
    col10,
)
EXEC [dbo].[usp_ProcedureName] @Para1, @Para2, @Para3, @Para4, @Para5, @Para6, @Para6

我希望这有帮助。请根据需要进行资格认证。

这个问题晚了几年,但我需要像这样的东西来快速生成肮脏的代码。我相信正如其他人所说的那样,预先定义临时表更容易,但这种方法应该适用于简单的存储过程查询或sql语句。

这将有点复杂,但它借鉴了这里的贡献者以及Paul White的DBA Stack Exchange Get存储过程结果列类型解决方案。再次重申,此方法和示例不是为多用户环境中的流程设计的。在这种情况下,表定义在全局临时表中被设置了一段时间,以供代码生成模板过程参考。

我还没有完全测试过这一点,所以可能会有一些警告,所以您可能需要转到Paul White的答案中的MSDN链接。这适用于SQL 2012及更高版本。

首先使用存储过程sp_describe_First_result_set,它类似于Oracle的description。

这将计算第一个结果集的第一行,因此如果存储过程或语句返回多个查询,它将只描述第一个结果。

我创建了一个存储过程来分解返回单个字段以创建临时表定义的任务。

CREATE OR ALTER PROCEDURE [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet]
(
     @sql NVARCHAR(4000)
    ,@table_name VARCHAR(100)
    ,@TableDefinition NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @TempTableDefinition NVARCHAR(MAX)
    DECLARE @NewLine NVARCHAR(4) = CHAR(13)+CHAR(10)

    DECLARE @ResultDefinition TABLE (  --The View Definition per MSDN
      is_hidden         bit NOT NULL
    , column_ordinal    int NOT NULL
    , [name]            sysname NULL
    , is_nullable       bit NOT NULL
    , system_type_id    int NOT NULL
    , system_type_name  nvarchar(256) NULL
    , max_length        smallint NOT NULL
    , [precision]       tinyint NOT NULL
    , scale             tinyint NOT 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 NOT NULL            
    , is_case_sensitive         bit NOT NULL            
    , is_fixed_length_clr_type  bit NOT 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_is_descending    smallint NULL   
    , order_by_list_length      smallint NULL
    , tds_type_id               int NOT NULL
    , tds_length                int NOT NULL
    , tds_collation_id          int NULL
    , tds_collation_sort_id     tinyint NULL
    )

    --Insert the description into table variable    
    INSERT @ResultDefinition
    EXEC sp_describe_first_result_set @sql

    --Now Build the string to create the table via union select statement
    ;WITH STMT AS (
        SELECT N'CREATE TABLE ' + @table_name + N' (' AS TextVal
        UNION ALL

        SELECT 
         CONCAT(
                CASE column_ordinal
                    WHEN 1 THEN '     ' ELSE '   , ' END  --Determines if comma should precede
                , QUOTENAME([name]) , '   ', system_type_name  -- Column Name and SQL TYPE
                ,CASE is_nullable 
                    WHEN 0 THEN '   NOT NULL' ELSE '   NULL' END --NULLABLE CONSTRAINT          
               ) AS TextVal
        FROM @ResultDefinition WHERE is_hidden = 0  -- May not be needed
        UNION ALL

        SELECT N');' + @NewLine
    ) 

    --Now Combine the rows to a single String
    SELECT @TempTableDefinition = COALESCE (@TempTableDefinition + @NewLine + TextVal, TextVal) FROM STMT

    SELECT @TableDefinition = @TempTableDefinition
END

难题是,您需要使用全局表,但需要使其足够独特因此您可以频繁地从中删除和创建,而不必担心冲突。在示例中,我使用Guid(FE264BF5_9C32_438F_8462_8A5DC8DE49E)作为全局变量,将连字符替换为下划线

DECLARE @sql NVARCHAR(4000) = N'SELECT @@SERVERNAME as ServerName, GETDATE() AS Today;'
DECLARE @GlobalTempTable VARCHAR(100) = N'##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable'

--@sql can be a stored procedure name like dbo.foo without parameters

DECLARE @TableDef NVARCHAR(MAX)

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

EXEC [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet] 
    @sql, @GlobalTempTable, @TableDef OUTPUT

--Creates the global table ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
EXEC sp_executesql @TableDef 

--Now Call the stored procedure, SQL Statement with Params etc.
INSERT ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
    EXEC sp_executesql @sql 

--Select the results into your undefined Temp Table from the Global Table
SELECT * 
INTO #MyTempTable
FROM ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

SELECT * FROM #MyTempTable

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

同样,我只使用简单的存储过程查询和简单的查询对其进行了测试,因此您的里程可能会有所不同。希望这对某人有所帮助。

在四处搜索之后,我找到了一种方法,可以在不使用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版本的模式(如果需要)。

存储过程是否只检索数据或修改数据?如果它仅用于检索,则可以将存储过程转换为函数并使用公共表表达式(CTE),而无需声明它,如下所示:

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

然而,需要从CTE中检索的内容只能在一个语句中使用。你不能用temp做。。。并尝试在几行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)