如何在不创建表的情况下将动态查询的结果存储在临时表中?

时间:2019-05-26 08:36:06

标签: sql sql-server

我们正在编写一个存储过程,负责获取存储过程的名称,并返回包含存储过程列及其数据类型的结果。 但是,我们遇到了执行动态查询以返回存储过程结果的问题,但是我们无法将其存储在临时表中!

您可以在下面看到我们的查询:

  DECLARE @ProcName VARCHAR(100)='spGetOraganizationsList',
  @ParamName VARCHAR(100),@DataType VARCHAR(20),
  @Query NVARCHAR(MAX)='EXEC '+'spGetOraganizationsList '

  SELECT  PARAMETER_NAME,DATA_TYPE 
  INTO #Tmp
  FROM  information_schema.PARAMETERS
  WHERE SPECIFIC_NAME=@ProcName

  DECLARE ParamCursor CURSOR 
  FOR SELECT * FROM #Tmp
  OPEN ParamCursor
  FETCH NEXT FROM ParamCursor
  INTO @ParamName,@DataType

  WHILE @@FETCH_STATUS = 0 
  BEGIN
  SET @Query=@Query+@ParamName+'=Null,'
  FETCH NEXT FROM ParamCursor INTO @ParamName,@DataType
  END
  CLOSE ParamCursor
  DEALLOCATE ParamCursor
  DROP TABLE #Tmp

  EXEC sp_executesql @Query

问题是我无法将其结果存储在临时表中, 并且OPENROWSET不接受变量。

6 个答案:

答案 0 :(得分:1)

我认为它来自sql概念,它不信任存储过程的结果,因此我们无法通过“在查询表中建立”方法对其进行选择或将其存储在表中。 除非创建表并定义它的列和sql对您的信任,然后将其结果插入该表中,否则请采取以下情况

Create table test (name varchar(10),family varchar(20))


Insert into test
Exec sp-testResult

现在,如果您为表定义了错误的列,您将收到查询运行时错误。实际上sql无法预测sp的结果,而是将其留给您来定义存储过程的结果。

答案 1 :(得分:0)

您当然可以将存储过程的结果插入TEMP表中:

CREATE PROCEDURE PurgeMe
AS
SELECT convert(int, 1) AS DaData
UNION
SELECT convert(int, 2)
GO

CREATE TABLE #Doodles  (AnInteger int)

INSERT #Doodles EXECUTE PurgeMe

SELECT * FROM #Doodles

但是,有关TEMP表的SCOPE的问题出现了。您可能会发现,在调用例程中,您将无法看到在例程中创建的TEMP表。

解决SCOPE问题的方法是执行以下操作:

  1. 创建一个最小的TEMP表(例如,只有一列)
  2. 在例程中的TEMP表上使用ALTER TABLE使其模式匹配 您的需求(这可能很棘手,但是可以做到)
  3. 将数据放入TEMP表
  4. 从例程返回-调用例程现在将能够访问临时 桌子

如果对此感兴趣,我可以使用存储过程进行更长的发布,以完成上述操作。它是为促进动态SQL而编写的

答案 2 :(得分:0)

使用全局临时表和动态OPENROWSET

  DROP TABLE ##Tmp;
  GO

  DECLARE @ProcName VARCHAR(100)='spGetOraganizationsList',
  @ParamName VARCHAR(100), @DataType VARCHAR(20),
  -- Mind to specify database and schema of the SP
  @Query NVARCHAR(MAX)=' EXEC [mydb].[dbo].spGetOraganizationsList ';
  SELECT  PARAMETER_NAME,DATA_TYPE 
  INTO #Tmp
  FROM  information_schema.PARAMETERS
  WHERE SPECIFIC_NAME=@ProcName;

  -- Build SP exec

  DECLARE ParamCursor CURSOR 
  FOR SELECT * FROM #Tmp
  OPEN ParamCursor
  FETCH NEXT FROM ParamCursor
  INTO @ParamName,@DataType

  WHILE @@FETCH_STATUS = 0 
  BEGIN
     SET @Query=@Query+@ParamName+'=Null,'
     FETCH NEXT FROM ParamCursor INTO @ParamName,@DataType
  END
  CLOSE ParamCursor
  DEALLOCATE ParamCursor
  SET @Query = left(@Query, len(@Query) - 1);

  -- Build ad hoc distributed query which creates ##Tmp from SP exec.

  SET @Query = 'SELECT * INTO ##Tmp FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'',''' + @Query + ''')';

  EXEC (@Query);

  -- Created by dynamic sql `##Tmp` is availabe in the current context. 
  SELECT *
  FROM ##Tmp;

别忘了首先启用即席分布式查询。

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

答案 3 :(得分:0)

在存储过程中根据需要编写选择查询。您无需创建临时表即可得到结果。

答案 4 :(得分:0)

在C#中,您可以使用SqlDataReader或DataTable从存储过程中获取结果,而无需事先了解架构。如果您随后想将该数据写入临时表,我想您可以从C#中做到这一点(尽管我从未尝试过这样做)。

答案 5 :(得分:-1)

为什么不创建视图而不是创建和删除表。

CREATE VIEW "VIEW_NAME" AS "SQL Statement";

一个不相关的示例:-

CREATE VIEW V_Customer
AS SELECT First_Name, Last_Name, Country
FROM Customer;