简体   繁体   English

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

[英]How to store results of a Dynamic Query in a temp table without creating a table?

We are writing a stored procedure responsible for getting a stored procedure name and returning a result containing the stored procedure columns and their data types.我们正在编写一个存储过程,负责获取存储过程名称并返回包含存储过程列及其数据类型的结果。 However, we bumped into a problem executing a dynamic query to return the results of stored procedure, but we can't store it in a temp table!但是,我们在执行动态查询以返回存储过程的结果时遇到了问题,但我们无法将其存储在临时表中!

You can see our query below:您可以在下面看到我们的查询:

  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

The thing is I can't store the results of it in a temp table, and OPENROWSET does not accept variables.问题是我无法将它的结果存储在临时表中,并且OPENROWSET不接受变量。

I think it comes from sql concept that it doesn't trust in result of stored procedures and because of that we cannot select on it or store it in a table by 'making in query table' method.我认为它来自 sql 概念,它不信任存储过程的结果,因此我们无法通过“在查询表中制作”方法对其进行选择或将其存储在表中。 Unless you create a table and define it's columns and sql trust to you and you insert result of it into this table for example take below situation除非您创建一个表并为您定义它的列和 sql 信任并将其结果插入到该表中,例如以下情况

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


Insert into test
Exec sp-testResult

Now if you define wrong column for your table you will receive query runtime error .actually sql doesn't predict result of sp and leaves it to you to define result of your stored procedure.现在,如果您为表定义了错误的列,您将收到查询运行时错误。实际上 sql 不会预测 sp 的结果,而是由您来定义存储过程的结果。

Why not create a view instead of creating and dropping the tables. 为什么不创建视图而不是创建和删除表。

CREATE VIEW "VIEW_NAME" AS "SQL Statement";

An unrelated example:- 一个不相关的例子:

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

You can certainly INSERT the results of a stored procedure into a TEMP table:您当然可以将存储过程的结果插入到 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

Questions arise about the SCOPE of TEMP tables, however.然而,关于 TEMP 表的 SCOPE 的问题出现了。 You might find that in your calling routine you will not be able to see a TEMP table created within your routine.您可能会发现,在您的调用例程中,您将看不到在例程中创建的 TEMP 表。

The solution to the SCOPE problem is to do the following: SCOPE 问题的解决方案是执行以下操作:

  1. Create a minimal TEMP table (say, with one column)创建一个最小的 TEMP 表(比如,只有一列)
  2. Use ALTER TABLE on the TEMP table within your routine to make its schema match your needs (this can be tricky, but it can be done)在例程中的 TEMP 表上使用 ALTER TABLE 使其架构符合您的需求(这可能很棘手,但可以做到)
  3. Put data into the TEMP table将数据放入 TEMP 表
  4. return from your routine - the calling routine will now be able to access the temp table从您的例程中返回 - 调用例程现在将能够访问临时表

If this is of interest I can make a longer post with a stored procedure to do the above.如果对此感兴趣,我可以使用存储过程制作更长的帖子来执行上述操作。 It was written to facilitate dynamic SQL它是为了方便动态 SQL 而编写的

Use global temp table and dynamic OPENROWSET使用全局临时表和动态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;

Don't forget to enable ad hoc distributed queries first.不要忘记首先启用即席分布式查询。

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

EDIT编辑

My answer solves only one problem, storing the result of a dynamic proc call in a temp table.我的回答只解决了一个问题,将动态 proc 调用的结果存储在临时表中。 And there are more problems.还有更多的问题。

First, @p=null just will not compile if the type of @p is user-defined table type.首先,如果@p的类型是用户定义的表类型, @p=null将不会编译。 You need kind of declare @t myType; exec mySp ... ,@p=@t ...你需要declare @t myType; exec mySp ... ,@p=@t ... declare @t myType; exec mySp ... ,@p=@t ... . declare @t myType; exec mySp ... ,@p=@t ... .

Next is the 'cannot retrieve matadata for sp because contain dynamic query' error you commented on.接下来是您评论的“无法检索 sp 的 matadata 因为包含动态查询”错误。 Looks like you need an application, SqlClr or standalone, which would be capable to read and parse Datasets returned by procs.看起来你需要一个应用程序,SqlClr 或独立的,它能够读取和解析 procs 返回的数据集。

Finally, if an SP contains conditional sql which can return a result set of different schema depending on parameter values, the result of all those efforts is still questionable.最后,如果一个 SP 包含条件 sql,它可以根据参数值返回不同模式的结果集,所有这些努力的结果仍然值得怀疑。

Write select query as you want in the stored procedure.在存储过程中根据需要编写选择查询。 You will get the result without creating temp table.您无需创建临时表即可获得结果。

In C#, you can use an SqlDataReader or a DataTable to get the results from a stored procedure without knowing the schema beforehand.在 C# 中,您可以使用 SqlDataReader 或 DataTable 从存储过程中获取结果,而无需事先知道架构。 If you then want to write that data to a temporary table, I think you can do that from C# (though I've never tried to do it).如果您想将该数据写入临时表,我认为您可以从 C# 中做到这一点(尽管我从未尝试过这样做)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM