簡體   English   中英

如何在不創建表的情況下將動態查詢的結果存儲在臨時表中?

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

我們正在編寫一個存儲過程,負責獲取存儲過程名稱並返回包含存儲過程列及其數據類型的結果。 但是,我們在執行動態查詢以返回存儲過程的結果時遇到了問題,但我們無法將其存儲在臨時表中!

您可以在下面看到我們的查詢:

  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不接受變量。

我認為它來自 sql 概念,它不信任存儲過程的結果,因此我們無法通過“在查詢表中制作”方法對其進行選擇或將其存儲在表中。 除非您創建一個表並為您定義它的列和 sql 信任並將其結果插入到該表中,例如以下情況

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


Insert into test
Exec sp-testResult

現在,如果您為表定義了錯誤的列,您將收到查詢運行時錯誤。實際上 sql 不會預測 sp 的結果,而是由您來定義存儲過程的結果。

為什么不創建視圖而不是創建和刪除表。

CREATE VIEW "VIEW_NAME" AS "SQL Statement";

一個不相關的例子:

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

您當然可以將存儲過程的結果插入到 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 而編寫的

使用全局臨時表和動態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

編輯

我的回答只解決了一個問題,將動態 proc 調用的結果存儲在臨時表中。 還有更多的問題。

首先,如果@p的類型是用戶定義的表類型, @p=null將不會編譯。 你需要declare @t myType; exec mySp ... ,@p=@t ... declare @t myType; exec mySp ... ,@p=@t ... .

接下來是您評論的“無法檢索 sp 的 matadata 因為包含動態查詢”錯誤。 看起來你需要一個應用程序,SqlClr 或獨立的,它能夠讀取和解析 procs 返回的數據集。

最后,如果一個 SP 包含條件 sql,它可以根據參數值返回不同模式的結果集,所有這些努力的結果仍然值得懷疑。

在存儲過程中根據需要編寫選擇查詢。 您無需創建臨時表即可獲得結果。

在 C# 中,您可以使用 SqlDataReader 或 DataTable 從存儲過程中獲取結果,而無需事先知道架構。 如果您想將該數據寫入臨時表,我認為您可以從 C# 中做到這一點(盡管我從未嘗試過這樣做)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM