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

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


当前回答

declare @temp table
(
    name varchar(255),
    field varchar(255),
    filename varchar(255),
    filegroup varchar(255),
    size varchar(255),
    maxsize varchar(255),
    growth varchar(255),
    usage varchar(255)
);
INSERT @temp  Exec sp_helpfile;
select * from @temp;

其他回答

如果存储过程的结果表太复杂,无法手动键入“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语句要简单得多,但它可以防止大型进程中出现诸如拼写错误和数据类型不匹配等手动错误。调试拼写错误可能比一开始编写查询要花费更多的时间。

如果让动态SQL创建一个临时表,则该表由动态SQL连接拥有,而不是从中调用存储过程的连接。

DECLARE @COMMA_SEPARATED_KEYS varchar(MAX);
DROP TABLE IF EXISTS KV;
CREATE TABLE KV (id_person int, mykey varchar(30), myvalue int);
INSERT INTO KV VALUES
(1, 'age', 16),
(1, 'weight', 63),
(1, 'height', 175),
(2, 'age', 26),
(2, 'weight', 83),
(2, 'height', 185);
WITH cte(mykey) AS (
    SELECT DISTINCT mykey FROM KV
) 
SELECT @COMMA_SEPARATED_KEYS=STRING_AGG(mykey,',') FROM cte;
SELECT @COMMA_SEPARATED_KEYS AS keys;

DECLARE @ExecuteExpression varchar(MAX);

DROP TABLE IF EXISTS #Pivoted;

SET @ExecuteExpression = N'
SELECT * 
INTO #Pivoted
FROM
(
    SELECT
        mykey,
        myvalue,
        id_person
    FROM KV
) AS t
PIVOT(
    MAX(t.myvalue) 
    FOR mykey IN (COMMA_SEPARATED_KEYS)
) AS pivot_table;
';

SET @ExecuteExpression = REPLACE(@ExecuteExpression, 'COMMA_SEPARATED_KEYS', @COMMA_SEPARATED_KEYS);

EXEC(@ExecuteExpression);

SELECT * FROM #Pivoted;

消息208,级别16,状态0对象名称“#Pivoted”无效。这是因为#Pivoted由动态SQL连接拥有。最后一条指令

SELECT * FROM #Pivoted

失败。

避免此问题的一种方法是确保所有对#Pivoted的引用都是从动态查询本身内部进行的:

DECLARE @COMMA_SEPARATED_KEYS varchar(MAX);
DROP TABLE IF EXISTS KV;
CREATE TABLE KV (id_person int, mykey varchar(30), myvalue int);
INSERT INTO KV VALUES
(1, 'age', 16),
(1, 'weight', 63),
(1, 'height', 175),
(2, 'age', 26),
(2, 'weight', 83),
(2, 'height', 185);
WITH cte(mykey) AS (
    SELECT DISTINCT mykey FROM KV
) 
SELECT @COMMA_SEPARATED_KEYS=STRING_AGG(mykey,',') FROM cte;
SELECT @COMMA_SEPARATED_KEYS AS keys;


DECLARE @ExecuteExpression varchar(MAX);

DROP TABLE IF EXISTS #Pivoted;

SET @ExecuteExpression = N'
SELECT * 
INTO #Pivoted
FROM
(
    SELECT
        mykey,
        myvalue,
        id_person
    FROM KV
) AS t
PIVOT(
    MAX(t.myvalue) 
    FOR mykey IN (COMMA_SEPARATED_KEYS)
) AS pivot_table;
SELECT * FROM #Pivoted;
';

SET @ExecuteExpression = REPLACE(@ExecuteExpression, 'COMMA_SEPARATED_KEYS', @COMMA_SEPARATED_KEYS);

EXEC(@ExecuteExpression);

当存储过程返回很多列,而您不想手动“创建”一个临时表来保存结果时,我发现最简单的方法是进入存储过程,在最后一个select语句上添加一个“into”子句,并在where子句中添加1=0。

运行一次存储过程,然后返回并删除刚才添加的SQL代码。现在,将有一个与存储过程结果匹配的空表。您可以为临时表“创建表脚本”,也可以直接插入到该表中。

如果您知道要传递的参数,并且您无权进行sp_configure,那么可以使用这些参数编辑存储过程,并将其存储在##全局表中。

如果OPENROWSET给您带来问题,从2012年起还有另一种方法;使用sys.dm_exec_descript_first_result_set_for_object,如下所述:检索存储过程的列名和类型?

首先,创建此存储过程以生成临时表的SQL:

CREATE PROCEDURE dbo.usp_GetStoredProcTableDefinition(
    @ProcedureName  nvarchar(128),
    @TableName      nvarchar(128),
    @SQL            nvarchar(max) OUTPUT
)
AS
SET @SQL = 'CREATE TABLE ' + @tableName + ' ('

SELECT @SQL = @SQL + '['+name +'] '+ system_type_name +''  + ','
        FROM sys.dm_exec_describe_first_result_set_for_object
        (
          OBJECT_ID(@ProcedureName), 
          NULL
        );

--Remove trailing comma
SET @SQL = SUBSTRING(@SQL,0,LEN(@SQL))    
SET @SQL =  @SQL +')'

要使用该过程,请按以下方式调用它:

DECLARE     @SQL    NVARCHAR(MAX)

exec dbo.usp_GetStoredProcTableDefinition
    @ProcedureName='dbo.usp_YourProcedure',
    @TableName='##YourGlobalTempTable',@SQL = @SQL OUTPUT

INSERT INTO ##YourGlobalTempTable
EXEC    [dbo].usp_YourProcedure

select * from ##YourGlobalTempTable

注意,我使用的是全局临时表。这是因为使用EXEC运行动态SQL会创建自己的会话,因此普通临时表将超出任何后续代码的范围。如果全局临时表有问题,可以使用普通临时表,但任何后续SQL都需要是动态的,也就是说,也可以由EXEC语句执行。