2012-06-29 76 views
7

我正在嘗試按照我的要求創建一個函數。在用戶定義的函數中創建,刪除和插入臨時表

但是,當正在創建或刪除#tempTable,它給一個錯誤:

一個函數中無效使用了副作用的運算符'一滴對象的

我的理解是我們不能在#temptable的函數中有createdropinsert操作。

這是正確的嗎?

我的SQL:

CREATE FUNCTION [dbo].[RT_ResultFunction] 
(
    Id VARCHAR(4000) 
) 
RETURNS @RT_ResultFunction TABLE 
( 
    Id VARCHAR(20) 
    , Name varchar(20) 
    ,Balance Int 
) 
AS 
BEGIN 
    IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL 
     DROP TABLE #tempTable 

    SELECT Id, COUNT(Balance) 
    INTO #tempTable 
    'Balance' FROM Table1 

    INSERT @RT_ResultFunction 
     SELECT T1.ID,T1,NAME,T2,Balance 
     FROM Table2 T1, 
       #tempTable T2 
     WHERE T1.ID = T2.ID 

    RETURN 
END 
+1

位對你的SQL感到困惑。如何在刪除後從#tempTable中選擇 - 它從未重新創建。 –

+0

請找到更新後的文章 –

+0

如果您想要解決此問題的幫助,請在函數內部解釋#temptable的要點。另外如何處理Id參數。 –

回答

19

這是正確的 - 你不能有副作用影響的語句:

從這裏:http://msdn.microsoft.com/en-us/library/aa175085(v=sql.80).aspx

的在BEGIN ... END塊不能報表有任何副作用。 功能副作用是對數據庫表的功​​能(如修改 )以外的範圍的 資源狀態的任何永久更改。函數中的 語句所做的唯一更改是對局部於 函數的對象(如局部遊標或變量)的更改。對 數據庫表的修改,對不在 函數本地的遊標的操作,發送電子郵件,嘗試目錄修改以及生成返回給用戶的結果集都是 的示例 無法在一個函數。

,你會發現什麼,即使沒有你的DROP說法是,任何試圖訪問一個臨時表會給你的消息(如SELECT ... INTO #TMP):

無法從內部訪問臨時表一個函數

作爲@Dems指出,你可以使用表變量。因爲這些是變量,所以它們被限制在函數中,因此不會產生副作用。

你的功能還不如運行:

... 

BEGIN 
    DECLARE @tempTable table (id varchar(20), rows int) 

    insert @tempTable 
    SELECT Id, COUNT(Balance) 
    FROM Table1 

    INSERT @RT_ResultFunction 
     SELECT T1.ID,T1,NAME,T2,Balance 
     FROM Table2 T1, 
       @tempTable T2 
     WHERE T1.ID = T2.ID 

    RETURN END 

沒有測試或任何東西,但你得到的要點。

+3

但是你可以使用表變量。這將是一個有用的事實,以添加到您的答案,以幫助OP解決他的問題*(而不只是知道爲什麼它是一個問題)*;) – MatBailie

+0

@Dems:好點 - 更新與更多的信息。 –

+0

當我讀到MSDN文檔後,我問自己:是否可以通過調用'function'中的'Stored Procedure'來修改表中的真實數據('INSERT' /'UPDATE' /'DELETE')?我想你不能,但我寧願確定會產生錯誤。你能告訴我,如果你知道嗎? :) –

2

我不知道爲什麼你需要在這個函數中使用#temp表格,或者爲什麼它首先是一個多語句的TVF。下面將要高效得多(雖然我不明白@Id參數的目的):

CREATE FUNCTION [dbo].[RT_ResultFunction] 
(
    @Id VARCHAR(4000) 
) 
RETURNS TABLE 
WITH SCHEMABINDING 
AS 
    RETURN 
    (
    SELECT T2.ID, T2.NAME, T1.Balance 
    FROM 
    (
     SELECT ID, Balance = COUNT(Balance) 
     FROM dbo.Table1 
     GROUP BY ID 
    ) AS T1 
    INNER JOIN dbo.Table2 AS T2 
    ON T1.ID = T2.ID 
); 

正如喬恩指出,我認爲它也可以重新寫成如下,它的其實如何我開始寫,但我沒有辦法證實如果這些實際上返回你試圖返回數據:

CREATE FUNCTION [dbo].[RT_ResultFunction] 
(
    @Id VARCHAR(4000) 
) 
RETURNS TABLE 
WITH SCHEMABINDING 
AS 
    RETURN 
    (
    SELECT T2.ID, T2.NAME, Balance = COUNT(T1.Balance) 
    FROM dbo.Table1 AS T1 
    INNER JOIN dbo.Table2 AS T2 
    ON T1.ID = T2.ID 
    GROUP BY T2.ID, T2.NAME 
); 
+0

正確 - 在這種情況下,臨時表是一種「奢侈品」,但它在任何情況下都是有用的。 (你也需要內部計數列上的別名)。 –

+0

@Jon ID和Name來自不同的表格。我不知道模式或數據,所以我試圖保持原始查詢的真實性。 –

0

刪除#改爲@使用我 沒有測試其它方面