運行時生成語句sql
一、用EXECUTE執行動態命令數據庫
EXECUTE命令能夠執行存儲過程、函數和動態的字符串命令。注意此語句的做用正如前面在介紹批處理時,若是批中的第一條語句是"EXECUTE存儲過程",則能夠 省略關鍵字"EXECUTE"。安全
語法:服務器
{ EXEC|EXECUTE } ( { @string_variable|[N]'tsql_string } [+...n] ) [ AS { LOGIN | USER } = 'name' ] [;]ide
參數說明:函數
EXEC:是EXECUTE的簡寫,二者皆可以使用。優化
@string_variable:局部變量的名稱,能夠是任意char、varchar、nchar或nvarchar數據類型,其中包括(max)數據類型。能夠將T-SQL代碼封裝在局部變量中 被執行。spa
[N]'tsql_string':常量字符串,可使任意nvarchar或varchar數據類型。若是包含N,則字符串將解釋成nvarchar數據類型。若是不是動態生成的字符串命令, 直接將其寫成常量字符串也能夠直接被執行。日誌
[ AS { LOGIN | USER } = 'name' ]:LOGIN指定執行的上下文(Context)爲登陸名,因此其執行範圍爲服務器級;USER指定執行的上下文爲用戶,因此其執行 範圍爲數據庫級。code
注意事項:EXECUTE在使用中可能致使SQL注入式***,即超越用戶自己權限的SQL語句可能會被執行,這樣在生成動態命令字符串時,能夠對字符串的內容進行 檢查。經過指定執行上下文,即便用[ AS { LOGIN | USER } = 'name' ]的語法形式,能夠限定EXECUTE語句的執行環境,確保安全。
二、用SP_EXECUTESQL執行動態命令
SP_EXECUTESQL是一個系統存儲過程,其功能和EXECUTE大體相同,不一樣的是其支持參數替換功能。而EXECUTE不支持參數替換功能。
功能:
執行能夠屢次重複使用或動態生成的T-SQL語句或批處理,能夠包含嵌入的參數。在批處理、臨時變量做用域和數據庫上下文上,SP_EXECUTESQL與EXECUTE 相同。
語法:
SP_EXECUTESQL [ @stmt= ] stmt [ {,[@params=] N'@parameter_name data_type [[OUT [PUT] [,...n]'} { ,[ @paraml = ]'value1'[,...n] } ]
參數說明:
[@stmt = ] stmt :包含T-SQL語句或批處理的Unicode字符串,必須是能夠隱式轉換爲ntext的Unicode常量或變量,但不能是表達式。使用字符串常量必須以N 做爲前綴。例如,Unicode常量N'sp_who'是有效的。但字符串常量'sp_who'則無效。字符串的大小僅受可用數據庫服務器內存限制。
[@params = ] N'@parameter_name data_type[,...n]':stmt中嵌入的全部參數定義的字符串。該字符串必須是可隱式轉換爲ntext的Unicode常量或變量。每 個參數定義由參數名稱和數據類型組成。在stmt中指定的每一個參數必須在@params中定義。若是stmt中的T-SQL語句或批處理不包含參數。則不須要@params。該 參數的默認值爲NULL。n是表示附加參數定義的佔位符。
[@params1 = ] 'value1':參數字符串中定義的第一個參數的值。該值可使常量或變量。必須爲stmt中包含的每一個參數提供參數值。若是stmt中的T-SQL語句 或批處理沒有參數,則不須要這些值。
OUTPUT:指示該參數是輸出參數。
N:附加參數的佔位符。這些值只能是常量或變量。不能是表達式。
代碼示例:
declare@sql_strnvarchar(200)declare@Idintset@Id=15set@sql_str='select * from person where Id = '+convert(varchar,@Id)execute sp_executesql @sql_str
三、參數替換
SP_EXCUTESQL和EXECUTE比較起來,其最大的特想在於參數替換,而EXECUTE語句不支持該功能。因爲EXECUTE不支持在執行的語句中包含參數,因此即便 對於下面這兩條功能徹底一致的,僅僅輸入值不一樣的語句,SQL Server引擎在執行時也須要從新編譯執行。
select * from person where Id = 275select * from person where Id = 276
反之,若是使用SP_EXECUTESQL來執行,咱們能夠編寫執行代碼以下,因爲僅僅是參數值的替換,因此引擎只須要編譯一次就能夠。
declare@intvariableint; declare@sqlstringnvarchar(500); declare@parmdefinitionnvarchar(500); set@stringsql= N'select * from person where Id = @pId'--第一次賦值執行set@parmdefinition=275EXECUTE sp_executesql @SQLString,@parmdefinition,@pId=@intvariable; set@parmdefinition=275--第二次賦值執行EXECUTE sp_executesql @SQLString,@parmdefinition,@pId=@intvariable;
與EXECUTE比較起來,SP_EXECUTESQL執行動態生成的字符串命令其有點以下:
一、參數替換帶來的高效率
就如上述SQL語句,對於只是參數不一樣的操做,SQLServer只須要編譯一次。 而若是用EXECUTE,SQLServer要編譯兩次。
字符串文本更改的後果,EXECUTE影響SQLServer查詢優化器將新的T-SQL字符串與現有的執行計劃相匹配的功能,而SP_EXECUTESQL的T-SQL的實際文本在 兩次執行之間未更改,因此查詢優化器可以將第二次執行中的T-SQL語句與第一次執行時生成的執行計劃相匹配。所以,SQLServer沒必要編譯第二條語句。
EXECUTE每次執行都要從新生成,而SP_EXECUTESQL只須要生成一次。
字符串的轉換,EXECUTE每次執行時都必須將參數值(非字符或Unicode值)轉換爲字符或Unicode格式。整型參數按其自己格式指定。不須要轉換爲Unicode。
二、執行計劃重用帶來的高效率。
使用SP_EXECUTE能夠重用SQL Server的執行計劃。屢次執行T-SQL語句且只更改了提供給T-SQL語句的參數值時,可使用SP_EXECUTESQL而不要使用存 儲過程。由於T-SQL語句自己保持不變,僅參數值發生更改,因此SQLServer查詢優化器可能會重用第一次執行時生成的執行計劃。
四、使用輸出參數的SP_EXECUTESQL
在使用SP_EXECUTESQL執行時,可使用參數。參數的使用有兩種類型,一種是輸入參數,一種是輸出參數。
輸入參數是將外部的值帶入到字符串命令中,輸出參數是將字符串執行結果返回到外部,一般是臨時變量中。
一、輸出參數的定義
在定義輸出參數時,使用OUTPUT關鍵字或(OUT)定義參數就能夠
語法格式:
{ [@params=] N'@parameter_name data_type OUTPUT }
二、獲取輸出參數的值
常見的獲取輸出參數的值的方法是在SP_EXECUTE語法中按照下面的形式。
SP_EXECUTESQL 執行的帶參數的字符串命令或變量 參數的定義字符串或變量 參數1名稱 = 參數1的值 ... OUTPUT
語句之間數據的傳遞
一、T-SQL語句之間的數據傳遞
(1)、局部變量傳遞數據
局部變量比如是一個批處理內部的數據公用存儲區,因此批處理內部的語句經過局部變量的名稱就能夠引用定義的變量數據。
(2)、參數傳遞數據
參數是在存儲過程和執行該存儲過程的批處理或腳本之間傳遞數據的對象。參數能夠是輸入參數也能夠是輸出參數。
參數的命名和形式和局部變量是徹底一致的,也須要說明參數的類型。二者不一樣的是局部變量是一個批處理內部傳遞數據的手段,而參數是跨越兩個代碼段或對 象傳遞數據的手段。
錯誤處理
(1)、SQLServer數據庫引擎錯誤
一、查詢系統錯誤信息
SQLServer在每一個數據庫的系統視圖sys.messages中存儲系統自定義(Message_id <= 50000)和用戶自定義(Message_id>50000)錯誤消息。
二、系統錯誤信息的嚴重性級別
獲得的系統錯誤消息分爲不一樣程度的嚴重性級別。嚴重性級別是經過數字來表示的,數字越小表示嚴重級別越低。反之則嚴重性越高。嚴重性較高的錯誤指示須要盡 快解決問題。
(2)、用try...catch發現錯誤
try...catch結構 begin try 要執行的T-SQL代碼,一旦錯誤將傳遞給catch塊進行處理 end try begin catch 檢索和處理錯誤信息的代碼 end catch 正常執行的T-SQL語句
try:其中,try塊是包含在begin try和end try之間的T-SQL代碼段,在該代碼段中一旦發生錯誤將傳遞給catch塊,若是沒有錯誤將直接執行catch塊後面的代碼。
catch:catch塊是包含在begin catch和end catch之間的T-SQL代碼段,在該代碼段中檢索和處理try塊中的錯誤信息。
(3)、捕獲錯誤的系統函數
一、error_number()
返回錯誤的ID號,對應sys.messages系統視圖中的message_id字段。
二、error_line()
返回T-SQL代碼中錯誤出現的語句行數。
三、error_message()
返回將返回給應用程序的消息文本。該文本包括爲全部可替換參數提供的值,如長度、對象名或時間。對應sys.messages系統視圖中的text字段。
四、error_procedure()
返回出現錯誤的存儲過程或觸發器名稱。若是在存儲過程或觸發器中未出現錯誤,該函數返回NULL。
五、error_severity()
返回錯誤的嚴重性級別。對應sys.messages系統視圖中的severity字段。
六、error_state()
返回狀態
示例:
begin try select1/0end trybegin catch select error_number() as'number', error_line() as'line', error_message() as'message', error_severity() as'severity', error_state() as'state'end catch
輸出結果如圖所示:
(4)、用@@ERROR捕獲上一條語句的錯誤
T-SQL還提供了一個簡單的系統函數@@ERROR來捕獲上一條語句的錯誤。若是上一條語句執行成功。@@ERROR系統函數將返回0;若是上一條語句生成錯誤, @@ERROR將返回錯誤號。
每條語句完成時@@ERROR都會更改。
例如:
select1/0select*from sys.messages where message_id =@@errorand language_id =2052
結果如圖:
(5)、用RAISERROR反饋錯誤
功能:
將生成的SQLServer引擎錯誤或警告信息(從sys.messages系統視圖得到)反饋到應用程序中。sys.messages系統視圖中由SQLServer自身定義的信息,其 message_id列的值小於等於5000。
返回用戶使用存儲過程sp_addmessage建立的自定義消息(存儲在系統視圖sys.messages中,其message_id大於50000)。
與print語句的區別:
print語句是T-SQL提供的用於反饋信息的語句,print語句只能反饋字符串或字符串表達式的值。
raiserror語句除了print語句的功能外,還支持相似C語言仲printf函數的字符串替換功能。這樣能夠先在字符串中定義要替換的數據的類型和位置,在輸出時自動 將字符串內容進行替換。
語法:
raiserror({ msg_id | msg_str |@local_variable }) { ,severity,state } [ ,argument [ ,...n ] ] ) [ with option [,...n] ]
參數說明:
msg_id:存儲在sys.messages系統視圖中的錯誤消息號(message_id)。若是是用戶使用as_addmessage系統存儲過程自定義的錯誤消息,其錯誤號應當大 於50000.若是未指定msg_id,則返回一個錯誤號爲50000的錯誤消息。
msg_str:用戶自定義消息,msg_str是一個字符串,具備可選的嵌入轉換規格。每一個轉換規格都會定義參數列表中的值。如何格式化並將其置於msg_str中轉 換規格位置上的字段中,轉換規格的格式以下:%[[flag][width][.precision][{h|1}]]type。
@local_variable:包含按照msg_str的方式格式化的字符串的任何有效字符串數據類型的變量。@local_variable的數據類型必須爲char或varchar,或者必須 可以隱式轉換爲這些數據類型。
severity:用戶定義的與該消息關聯的嚴重級別。當使用msg_id引起使用sp_addmessage建立的用戶定義消息時,paiserror上指定的嚴重性將覆蓋 sp_addmessage中指定的嚴重性。
state:狀態號,1至少127之間的任意整數。若是在多個位置引起相同的用戶自定義錯誤,則針對每一個位置使用惟一的狀態好有助於找到引起錯誤的代碼段。
argument:用於代替msg_str或對應於msg_id的消息中的定義的變量的參數。能夠有0個或多個替代參數,可是替代參數的總數不能超過20個。
option:錯誤的自定義選項。LOG:在SQLServer數據庫引擎實例的錯誤日誌和應用程序日誌中記錄錯誤;NOWAIT:將消息當即發送給客戶端;SETERROR:將 @@ERROR值和ERROR_NUMBER值設置爲msg_id或50000,不用考慮嚴重級別。