1 存儲過程簡介sql
存儲過程(Stored Procedure)是爲了完成特定的功能而聚集成一組的SQL語句集,併爲該組SQL語句命名、經編譯後存儲在SQL Server的數據庫中。用戶能夠 根據須要決定是否在每次執行時讓SQL Server進行從新編譯。用戶能夠指定存儲過程的名字和給出參數來執行它。 容許多個用戶(有權)訪問相同的代碼。 提供一種集中且一致的實現數據完整性邏輯的方法。 存儲過程用於實現:頻繁使用的查詢;業務規則;被其餘過程使用的公共例行程序;例如錯誤處理例行程序等。
1.1 存儲過程的優勢
使用存儲過程可加快運行速度、可減小網絡交通可重用、可共享性。存儲過程也是一種安全機制,使用存儲過程實現數據庫完整性,提升數據與應用的獨立性。
1.2 存儲過程的分類
系統存儲過程:系統提供存儲過程,用於從系統表中獲取信息、爲系統管理員和有權用戶提供更新系統表的途徑。系統存儲過程的名字都以"sp_"爲前綴。 如:sp_help 。 用戶定義的存儲過用戶定義存儲過程是由用戶爲完成某一特定功能而編寫的存儲過程。數據庫
例如:在SQL Server安裝時自動創建了一些以sp_爲前綴的系統存儲過程, 這些系統過程一般用來顯示或修改系統表它們可爲各用戶所共享。express
2 存儲過程的建立、修改、刪除
2.1 建立存儲過程安全
create proc procedure_name as begin SQL_statements [return] end
2.1 建立存儲過程
存儲過程被放在當前正在使用的數據庫中。 在存儲過程當中能夠引用在其餘數據庫中的對象。建立存儲過程(create proc)語句不能與其餘的SQL語句在同一個批中,即建立存儲過程語句必須單獨成爲一個批。 在存儲過程當中能夠包含SQL語句,可是不能包含:use, create view, create rule, create default, create proc, create trigger
2.2 執行存儲過程網絡
exec procedure_name [參數]; execute procedure_name [參數];
2.3 查看存儲過程oop
--查看存儲過程 查看建立存儲過程的源代碼,使用: procedure_name sp_helptext; --查看存儲過程所依賴的表和視圖信息,使用: sp_depends procedure_name ; --查看存儲過程的通常信息,如建立日期等,使用: sp_help procedure_name;
2.3 重命名存儲過程fetch
--從新命名存儲過程 語法: sp_rename old_name , new_name ; --語法 例:將已建立的存儲過程reports_1更名爲reports_1b: exec sp_rename reports_1, report_lb;
2.3 刪除存儲過程this
--刪除存儲過程 語法: drop proc procedure_name; -- 語法 例: 刪除已建立的存儲過程reports: drop proc reports;
2.4 存儲過程當中的註釋spa
SQL Server提供了兩種在T-SQL中的註釋方法: 1使用斜槓星號對/* 注示內容*/ 。 例如: /* bind the rule to all columns with datatype */ exec sp_bindrule ul_tid,tid 2或使用雙連字符 -- 例如: --bind the rule to all columns --with datatype tid exec sp_bindrule ul_tid,tid
3 存儲過程當中的參數、返回值和變量
3.1 存儲過程當中的參數
輸入參數(Input Parameters) 是指由調用程序向存儲過程提供的變量值。它們在建立存儲過程語句中被定義,而在執行該存儲過程語句中給出相應的變量值。使用輸入參數的優勢是使存儲過程得更加靈活。
--語法: create proc procedure_name (@parameter_name datatype [, @parameter_name datatype……]) as begin SQL_statements return end
3.1.1 帶參數存儲過程
舉例: 建立帶參數的存儲過程 create proc proc_author_addr (@lname varchar(40)) as begin select phone, address, city, state from authors where au_lname = @lname return end -- 在調用程序的執行存儲過程命令中,將相應的值傳遞給 -- 這個輸入參數:用'Green'替換@lname exec proc_author_addr @lname = 'Green' ; --沒見過 --或 exec proc_author_addr 'Green' end; --沒見過 exec proc_author_addr('Green'); --經常使用
3.1.2 帶有返回參數的存儲過程
建立向調用程序返回值的存儲過程: create proc proc_num_sales ( @book_id char(6) = null, /* 輸入參數*/ @tot_sales int output /* 輸出參數*/ as begin /* 過程將返回對於給定書號的書的總銷售量*/ select @tot_sales = sum(qty) from salesdetail where title_id = @book_id return end
3.2 存儲過程返回狀態
每一個存儲過程的執行,都將自動返回一個返回狀態,用於告知調用程序執行該存儲過程的情況。調用程序可根據返回狀態做相應的處理。
語法 create proc procedure_name ( ……) as begin SQL_statements return [ integer ] end
其中:integer爲一整數。若是不指定,系統將自動返回一個整數值。系統使用0表示該過程執行成功;-1至¨C14 表示該過程執行有錯,-15至-99爲系統保留值。用戶通常使用大於0的整數,或小於-100的負整數。
3.3 存儲過程當中的變量:局部變量;全局變量。
3.3.1 局部變量
局部變量:用戶自定義變量。使用declare語句定義。具備名和數據類型,經過用戶賦值,說明時給變量賦值爲空,局部變量可在存儲過程,或觸發器中定義。
--局部變量的定義與聲明 DECLARE @var_name data_type [, @var_name data_type] …… declare @msg varchar(40) declare @myqty int, @myid char(4) --爲局部變量賦值。局部變量被聲明時, 它的初值爲NULL , 使用SELECT語句將指定值賦給局部變量。 select @var = expression [,@var = expression ] [from…[where…]… declare @var1 int select @var1=99
注意 : 在一個賦值給局部變量的select 語句中, 可使用常數、 從表中取值、或使用表達式給局部變量賦值。 不能使用同一SELECT 語句既給局部變量賦值,又檢索數據返回給客戶。一個賦值給局部變量的SELECT 語句,不向用戶顯示任何值。
對局部變量的限制
局部變量必須先用DECLARE定義,再用SELECT語句賦值後才能使用。 局部變量只能使用在T-SQL語句中使用常量的地方。 局部變量不能使用在表名、列名、其它數據庫對象名、保留字使用的地方。 局部變量是標量,它們擁有一個確切的值。 賦值給局部變量的SELECT語句應該返回單個值。若是賦值的SELECT語句沒有返 回值,則該局部變量的值保持不變;若是賦值的SELECT語句返回多個值,則該局部變量取最後一個返回的值。
使用局部變量時一般發生的錯誤
在程序中, 使用局部變量一般容易發生的錯誤是數據類型不匹配。 即便用DECLARE 語句定義局部變量的數據類型與賦值給局部變量的值的數據類型不匹配。 若是發生這種狀況,SQL Server 老是試圖隱式轉換爲局部變量的數據類型。
3.3.2 全局變量
全局變量( Gloabal Variable )是SQL Server系統提供並賦值的變量。 用戶不能創建全局變量,也不能使用SELECT語句去修改全局變量的值。全局變量的名字用@@開始。大多數全局變量的值報告本次SQL Server啓動後發生的系統活動,可使用系統存儲過程sp_monitor顯示全局變量的當前值。一般全局變量的值賦給在同一批中的局部變 量,以便保存和做進一步處理
--經常使用的全局變量 @@error --由最近一個語句產生的錯誤號; @@rowcount --被最近一個語句影響的行數; @@version --SQL Server的版本號; @@max_connections --容許與該SQL Server鏈接的最大用戶個數; @@Servername --該SQL Server的名字 --全局變量舉例 select @@version declare @book_price money select @book_price = price from titles where title_id = 'BU1032' if @@rowcount = 0 print 'no such title_id' else begin print 'title_id exists with'
select 'price of' = @book_price end
4 存儲過程當中的流程控制語言
流程控制SQL語句的執行順序,這在存儲過程、觸發器、批中很是有用。流控制關鍵字(命令)包括:IF ELSE;IF EXISTS 和IF NOT EXISTS BEGIN…END RETURN WHILE BREAK和CONTINUE WAITFOR PRINT
4.1 IF ELSE / else if / End if
--IF ELSE --部分語法(ASE) if boolean_expression statement [else [if boolean_expression1] statement1 ] --部分語法(IQ) if boolean_expression then statement [else [if boolean_expression1] statement1 ] End if
4.2 IF EXISTS 和IF NOT EXISTS
--當你關心數據是否存在時,在IF 語句中使用[NOT] EXISTS 是頗有用的。 --語法(ASE) 語法 if [not] exists (select statement) statement block --舉例(ASE) 舉例/* 是否存在姓「Smith」的做者*/ declare @lname varchar(40) select @lname = 'Smith' if exists ( select * from authors where au_lname = @lname) select 'here is a ' + @lname else select 'here is no author called'+@lname
4.3 BEGIN…END
功能:當須要將一個以上的SQL 語句做爲一組語句對待時, 可使用BEGIN 和END 將它們括起來造成一個SQL 語句塊。從 語法上看,一個SQL 語句塊至關於一個SQL 語句。在流控制語言中, 容許用一個SQL語句塊替代單個SQL語句出現的地方。
語法BEGIN statement block END 這裏:statement block 一般爲一個以上的SQL 語句。固然也但是 一個SQL語句。
4.4 RETURN
功能RETURN:命令無條件退出它所在的批、 存儲過程或觸發器。 退出時,能選擇提供返回狀態。RETURN 語句以後的任何語句不被執行。
語法RETURN [integer_expression]
if not exists ( select * from titles where title_id = @t_id) begin print 'here is no title by this title_id' return --無條件退出批,其後語句不被執行。 insert salesdetail values(@s_id, @o_num, @t_id,@qty_sold, @disc) end go
4.5 WHILE
功能:WHILE關鍵字爲要重複執行的某一語句或語句塊設置條件, 當指定的條件爲真(TRUE )時,執行這一語句或語句塊, 直到條件爲假( FALSE ) 或執行BREAK 語句。語句塊是由BEGIN 和END 括起來的兩個或兩個以上的語句構成。
--語法(ASE) 語 while boolean exprission statement block --語法(IQ) 語法 while boolean exprission loop statement block end loop --舉例 while (select avg(price) from titles) < $40 begin select title_id, price from titles where price > $20 update titles set price = price + $2 end select title_id, price from titles print "Too much for the market to bear"
4.6 BREAK和CONTINUE
功能:BREAK和CONTINU關鍵字控制在WHILE循環中語句塊中語句的執行。BREAK關鍵字將退出它所在的循環,繼續執行後面的語句(即跳過從關鍵字BREAK到它所在循環結束END之間的全部語句);CONTINU關鍵字使循環從新開始,即跳過任何在該循環內但在CONTINU關鍵字以後的語句。
--語法(ASE) 語法 WHILE boolean expression BEGIN statement1 statement2 BREAK CONTINU END statement --舉例(ASE) 舉例 while (select avg(price) from titles) >= $20 begin update titles set price = price / 2 if (select max(price) from titles) < $40 break else if (select avg(price) from titles) < $20 continu print "Average price still over $20" end print "Not too expensive.or Average price under $20"
4.7 WAITFOR
功能:WAITFOR 關鍵字將掛起當前的執行, 直到指定的事件發生。它經常被系統用來實現有規律的系統維護、出錯處理、 事件處理和統計記錄等。
部分語法waitfor {delay time | time time |……}
--舉例 這個例子是一個無終止循環,它每隔半小時記錄一次鎖的個數。 while 2>1 /* 這一表達式老是返回'TRUE' */ waitfor delay '0:30:00' /* 每隔30分鐘*/ insert into num_procs select getdate(), count(*) from master, syslocks
4.8 PRINT
功能:PRINT關鍵字用來在屏幕上顯示用戶定義的信息,局部變量的值或char/varchar類型的全局變量的值。
--語法 print {"any ascii characters or string" |local_variable | global_variable } [, arg_list ] --舉例(1) print "hello" --(2) print @msg /* @msg 是一個局部變量。*/ --(3) declare @table_name varchor(30) , @user_name varchar(30) select @table_name = "titles", @user_name = "ezekiel" print "The table%1! is not owned by the user %2!",@table_name ,@user_name
5 存儲過程當中的事務、遊標
5.1 嵌套事務
嵌套事務是指在存儲過程當中的事務的間接嵌套, 即嵌套事務的造成是由於調用含有事務的過程。
@@trancount 記錄了事務嵌套級次。@@trancount在第一個begin tran語句後值爲1,之後每遇到一個begin tran 語句,不管是否在嵌套 過程當中,@@trancount的值增長1;每遇到 一個commit,@@trancount的值就減小1。若@@trancount的 值 等於 零,表示當前沒有事務;若@@trancount的值不等於零,其值假定爲i,代表當前處於第i 級嵌套事務中。對於嵌套事務,直到 使用@@trancount 的值爲零的那個commit語句被執行,整個事務才被提交。select @@trancount
5.1.1 與事務相關的語句
Rollback 根據SQL Server的缺省規定,一個不帶事務名或保存 點名的rollback tran 語句,不論它是否在嵌套事務中, 老是退到最外 面的begin tran語句,即回退包括全部 嵌套事務在內的整個事務commit 根據SQL Server的缺省規定,即便是在嵌套事務中 執行commit 語 句,@@trancount計數值也只減小1。
5.2 存儲過程當中的遊標
create proc procedure_name as SQL_statements containing cursor processing --其中:SQL_statements containing cursor processing 是指包含遊標處理的SQL語句。 --舉例 create proc proc_fetch_book As begin declare @book_title char(30), @book_id char(6) declare biz_book cursor for select title, title_id from titles where type = "business" open biz_book fetch biz_book into @book_title, @book_id ……-- 在這裏作某些處理 close biz_book deallocate cursor biz_book return end
5.2 存儲過程當中的遊標
遊標的做用域:若是存儲過程是嵌套的話,那麼也包括它的全部子域。這就是說,若是嵌套的存儲過程構成一棵調用樹(Call Tree),那麼在 這棵樹的某個結點上定義的遊標,其做用域就是它位於的樹叉,即自定義遊標的那個結點的存儲過程及它所包含的全部子域。可是若是 在它所包含的子域中,定義了與它同名的遊標,那麼它將在定義同名遊標的子域內及該子域所包含的其餘子域內失效。
6 ASE存儲過程和IQ存儲過程常見區別、舉例
COMMIT 在IQ存儲過程當中, 每個增、 刪、 改、 查的上sql 後都要加上一個commit以保證語句成功執行(ASE不用); BEGIN END ASE的存儲過程的每一個程序分支要放在BEGIN END中(每一個條件判斷,每一個循環等); IQ不用,只要在程序最外邊有個BEGIN END 就能夠了; ASE存儲過程要在存儲過程名以後,BEGIN以前加上@,IQ不用變量定義 ASE:DECLARE @ date_begin CHAR(8); IQ:DECLARE date_begin CHAR(8); 變量賦值 ASE存儲過程當中:select @sql_str = '123' IQ存儲過程當中:select '123' into sql_str 變量引用 ASE存儲過程當中:@+變量名 IQ存儲過程當中:變量名