[英]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 問題的解決方案是執行以下操作:
如果對此感興趣,我可以使用存儲過程制作更長的帖子來執行上述操作。 它是為了方便動態 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.