剛開始時,這個表的字段很少(10個以內),前開發者把這個表的所有存儲過程與觸發器以及表函數全是寫死了。用戶每添加一些字段,都需要手動去更改這些存儲過程與觸發器以及表函數。現在這個表的字段已經高達300個以上,有可能還會增長,因此Insus.NET的業務就是把這此靜態全改寫為動態處理。
然而有一個問題一直困攏至昨天,昨天是星期天本應是休息的,但是這個問題沒有解決,因此這天算不上休息了。
問題就是改寫表的觸發器,涉及到EXEC(EXECUTE)函數訪問INSERTED或DELETED的內部臨時觸發表,如:
復制代碼 代碼如下:
EXECUTE('SELECT '+ @N +' = ISNULL(['+ @I +'],0) FROM inserted')
當你嘗試執行上面的SQL語句,會得到一個異常提示:invalid object name 'inserted'。我們無法顯示訪問INSERTED或DELETED的內部臨時觸發表。
由於INSERTED或是DELETED表是動態駐留在內存中,而不是存儲在數據庫中,它不是顯式的。觸發器的執行是在導致觸發器被觸發的執行計劃中。當我們使用EXEC(EXECUTE)或sp_executesql執行動態生成的SQL語句時,它卻是另外一個單獨的執行計劃。兩者之間的資源無法相互訪問,再加上計劃執行完畢,內存也隨之釋放資源了。
但是問題還是需要解決,Insus.NET想起的還是臨時表。可以把INSERTED或DELETED表中的數據,首先轉換入臨時表了。這樣子,我們就可以對臨時表的數據進行處理了。
復制代碼 代碼如下:
SELECT * INTO #inserted FROM INSERTED
SELeCT * INTO #deleted FROM DELETED
實現代碼:
復制代碼 代碼如下:
DECLARE @F NVARCHAR(MAX) = CONVERT(NVARCHAR(MAX),@I) --@I動態字段
EXECUTE ('SELECT ['+ @F +'] FROM #deleted)