Transact-SQL中的儲存過程,非常類似於C#語言中的方法,可以重複呼叫。當儲存過程執行一次後,可以將語句儲存到快取中,這樣下次執行的時候直接使用快取中的語句。這樣就可以提高儲存過程的效能。
一、儲存過程的概念
儲存過程Procedure是一組為了完成特定功能的SQL語句集合,儲存在資料庫中,經過第一次編譯後再次呼叫不需要再次編譯,使用者通過指定儲存過程的名稱並給出引數來執行。
儲存過程中可以包含邏輯控制語句和資料操縱語句,它可以接受引數、輸出引數、返回單個或多個結果集以及返回值。
由於儲存過程在建立時即在資料庫伺服器上進行了編譯並儲存在資料庫中,所以儲存過程執行要比單個的SQL語句塊要快。同時由於在呼叫時只需用提供儲存過程名和必要的引數資訊,所以在一定程度上也可以減少網路流量、簡單網路負擔。
1、 儲存過程的優點
A、 儲存過程允許標準元件式程式設計
儲存過程建立後可以在程式中被多次呼叫執行,而不必重新編寫該儲存過程的SQL語句。而且資料庫專業人員可以隨時對儲存過程進行修改,但對應用程式原始碼卻毫無影響,從而極大的提高了程式的可移植性。
B、 儲存過程能夠實現較快的執行速度
如果某一操作包含大量的T-SQL語句程式碼,分別被多次執行,那麼儲存過程要比批處理的執行速度快得多。因為儲存過程是預編譯的,在首次執行一個儲存過程時,查詢優化器對其進行分析、優化,並給出最終被存在系統表中的儲存計劃。而批處理的T-SQL語句每次執行都需要預編譯和優化,所以速度就要慢一些。
C、 儲存過程減輕網路流量
對於同一個針對資料庫物件的操作,如果這一操作所涉及到的T-SQL語句被組織成一儲存過程,那麼當在客戶機上呼叫該儲存過程時,網路中傳遞的只是該呼叫語句,否則將會是多條SQL語句。從而減輕了網路流量,降低了網路負載。
D、 儲存過程可被作為一種安全機制來充分利用
系統管理員可以對執行的某一個儲存過程進行許可權限制,從而能夠實現對某些資料訪問的限制,避免非授權使用者對資料的訪問,保證資料的安全。
二、儲存過程的分類
1、系統儲存過程
以sp_開頭,用來進行系統的各項設定.取得資訊.相關管理工作。系統儲存過程是系統建立的儲存過程,目的在於能夠方便的從系統表中查詢資訊或完成與更新資料庫表相關的管理任務或其他的系統管理任務。系統儲存過程主要儲存在master資料庫中,以“sp”下劃線開頭的儲存過程。儘管這些系統儲存過程在master資料庫中,但我們在其他資料庫還是可以呼叫系統儲存過程。有一些系統儲存過程會在建立新的資料庫的時候被自動建立在當前資料庫中。
[{@引數名稱 引數資料型別} [=預設值] [output],
{@引數名稱 引數資料型別} [=預設值] [output],
....
]
as
SQL_statements
--建立測試表MyStudentInfo
CREATE table MyStudentInfo
(
Id int not null primary key,
Name varchar(16),
Age int,
Gender varchar(2),
Phone varchar(16),
Address varchar(50),
GradeId int,
Score int
)
--聯合插入多條資料
INSERT INTO MyStudentInfo
SELECT 1,'張三',20,'1','15801258912','上海',1,90 UNION
SELECT 2,'李四',22,'1','12345678901','北京',1,84 UNION
SELECT 3,'王五',16,'1','13976891234','天津',2,35 UNION
SELECT 4,'趙六',19,'1','18676891234','重慶',3,56 UNION
SELECT 5,'小紅',21,'2','17776891234','廣州',4,82 UNION
SELECT 6,'小王',25,'2','13176891234','深圳',5,54 UNION
SELECT 7,'小劉',18,'2','13374591234','南京',6,69 UNION
SELECT 8,'小張',16,'1','13974596734','長沙',6,58 UNION
SELECT 9,'小羅',27,'1','13175122786','武漢',7,40 UNION
SELECT 10,'小袁',21,'2','17715872346','石家莊',8,34
CREATE table GradeInfo
(
Id int not null primary key,
GradeName varchar(16)
)
--聯合插入多條資料
INSERT INTO GradeInfo
SELECT 1,'.NET' UNION
SELECT 2,'Android' UNION
SELECT 3,'PHP' UNION
SELECT 4,'UI' UNION
SELECT 5,'HTML5' UNION
SELECT 6,'JAVA' UNION
SELECT 9,'HADOOP' UNION
SELECT 10,'大資料'
--1、不帶引數的儲存過程,獲取MyStudentInfo表的所有記錄
CREATE proc Proc_GetInfo
as
select * from MyStudentInfo
--執行儲存過程
exec Proc_GetInfo
go
--2、建立帶輸入引數的儲存過程
CREATE proc Proc_InsertData
@Id int,
@Name varchar(16),
@Age int,
@Gender varchar(2),
@Phone varchar(16),
@Address varchar(50),
@GradeId int,
@Score int
as
begin
insert INTO MyStudentInfo VALUES(@Id,@Name,@Age,@Gender,@Phone,@Address,@Gender,@Score)
end
--執行儲存過程
exec Proc_InsertData @Id=11,@Name='小李',@Age=21,@Gender='2',@Phone='13981257512',@Address='太原',@GradeId=4,@Score=62
GO
--3、建立帶預設值的輸入引數的儲存過程
CREATE proc Proc_InsertDefault
@Id int,
@Name varchar(16),
@Age int,
@Gender varchar(2)='1',
@Phone varchar(16),
@Address varchar(50)='瀋陽',
@GradeId int,
@Score int
as
begin
insert INTO MyStudentInfo VALUES(@Id,@Name,@Age,@Gender,@Phone,@Address,@Gender,@Score)
end
--執行儲存過程
exec Proc_InsertDefault @Id=12,@Name='小阮',@Age=24,@Phone='13832757512',@GradeId=4,@Score=70
GO
--4、建立帶輸出引數的儲存過程(根據輸入的ID返回年級ID)
--在建立儲存過程時,可以用關鍵字OUTPUT來建立一個輸出引數,另外,呼叫時也必須給出OUTPUT關鍵字
create proc Proc_Out
@Id int,
@gradeId int out
as
begin
select @gradeId=GradeId from MyStudentInfo where id=@id
end
--執行儲存過程
declare @GradeIdOut int
exec Proc_Out 10,@GradeIdOut out
print @GradeIdOut
GO
--執行儲存過程
DECLARE @Sid int
EXEC Proc_Out @gradeId=@Sid OUT,@Id=10
PRINT @Sid
--5、建立帶返回值的儲存過程
--print語句可以將使用者定義的訊息返回給客戶端
--編寫一個儲存過程,在插入學生資料前,先判斷學號是否存在,如果存在,
--輸出“要插入的學生的學號已經存在”;否則,插入學生資料,返回“恭喜,資料插入成功”
create proc Proc_Return
@Id int,
@Name varchar(16),
@Age int,
@Gender varchar(2),
@Phone varchar(16),
@Address varchar(50),
@GradeId int,
@Score int
as
begin
IF exists (SELECT * FROM MyStudentInfo WHERE Id=@Id)
begin
print '要插入的學生的學號已經存在'
ROLLBACK
end
else
begin
insert INTO MyStudentInfo VALUES(@Id,@Name,@Age,@Gender,@Phone,@Address,@GradeId,@Score)
print '恭喜,資料插入成功'
end
end
GO
--執行儲存過程
exec Proc_Return @Id=10,@Name='小李',@Age=21,@Gender='2',@Phone='13981257512',@Address='太原',@GradeId=4,@Score=75
--執行儲存過程
exec Proc_Return @Id=12,@Name='小李',@Age=21,@Gender='2',@Phone='13981257512',@Address='太原',@GradeId=4,@Score=75
--()return 語句,return語句可以從過程、批處理或語句塊中退出,不執行其後繼語句
CREATE proc Proc_Delete
@name varchar(16)
as
begin
delete FROM MyStudentInfo where Name=@name
return @@rowcount
end
--呼叫儲存過程
declare @Del_Row int
exec @Del_Row= Proc_Delete @name='小劉'
select @Del_Row 刪除的行
GO
--6、建立帶變數的儲存過程
/*在儲存過程可以定義變數,包括全域性變數(@@變數名)和區域性變數(@變數名)。
用於儲存儲存過程中的臨時結果。
編寫儲存過程Proc_Var,根據輸入的學生學號,計算該學生的平均成績。
根據該生平局成績與全體學生平均成績的關係,返回相應資訊*/
create proc Proc_Var
@id int,
@ResStr varchar(16) out
as
begin
--宣告變數
declare @curAvg decimal(18,2)
declare @totalAvg decimal(18,2)
select @totalAvg=AVG(Score) from MyStudentInfo
select @curAvg=AVG(Score) from MyStudentInfo where Id=@id
IF @curAvg>@totalAvg
set @ResStr='高於平均分'
else
set @ResStr='低於平均分'
print '總平均分為:'+convert(varchar(18),@totalAvg)
print '該生平均分為:'+convert(varchar(18),@curAvg)
print @ResStr
end
--呼叫儲存過程
declare @resstring varchar(20)
exec Proc_Var 6,@resstring out
--7、建立帶輸入輸出引數的儲存過程
create proc Proc_OutPut
@Id int,--預設輸入引數
@Score int out,--輸出引數
@Age int output --輸入輸出引數
as
begin
select @Score=Score,@Age=Age from MyStudentInfo where Id=@Id and Age=@Age
end
--執行儲存過程
declare @Sid int,@SScore int,@SAge int
set @Sid=8
set @SAge=16
exec Proc_OutPut @Sid,@SScore out,@SAge output
print '成績:'+convert(varchar(8),@SScore)+',年齡:'+convert(varchar(8),@SAge)
--8、建立分頁儲存過程
create proc Proc_Page
@StartIndex int,
@EndIndex int
as
begin
select COUNT(*) from MyStudentInfo
select * from (
SELECT ROW_NUMBER() OVER(ORDER BY Id) AS rowid,* FROM MyStudentInfo ) temp
where temp.rowid between @StartIndex AND @EndIndex
end
--執行儲存過程
exec Proc_Page 1,4
--分頁儲存過程2
create proc Proc_P
@PageIndex int,
@PageSize int
as
begin
declare @StartRow int,@EndRow int
set @StartRow=(@PageIndex-1) * @PageSize +1
set @EndRow =@StartRow+@PageSize-1
select * from (
SELECT ROW_NUMBER() OVER(ORDER BY Id ASC) as rowid ,* FROM MyStudentInfo ) temp
where temp.rowid between @StartRow AND @EndRow
end
--執行儲存過程
exec Proc_P 2,4