SqlServer:存儲過程


存儲過程

存儲過程(Stored Procedure)簡稱過程,由一系列SQL語句構成完成一定的功能的程序段,通過過程名調用並執行。在 SqlServer 中存放在數據庫的“可編程性”組件中,與表和視圖的級別相同。存儲過程是由流程控制和 SQL 語句組成的,允許用戶聲明變量,可以調用系統函數,經編譯后存儲在數據庫服務器中。存儲過程可以接收輸入參數,也可以將運行結果帶出過程,返回執行存儲過程的狀態值,還可以嵌套調用。由於存儲過程在服務器運行,且運行后會保存在緩存中,因此可以提高運行效率。
存儲過程分為三類,分別是系統存儲過程、用戶自定義存儲過程和擴展存儲過程。

存儲過程類型 說明
系統存儲過程 系統自動創建的系統存儲過程,用於顯示各種參數等,以 “sp_” 為前綴
自定義存儲過程 由用戶為完成某一特定功能而編寫的存儲過程,名稱不能以 “sp_” 為前綴
擴展存儲過程 是對動態鏈接庫(DLL)函數的調用,前綴名是 “XP_”

創建存儲過程的步驟是:

  1. 檢驗存儲過程名是否存在;
  2. 編寫存儲過程中的 SQL 語句;
  3. 用創建存儲過程的語法創建存儲過程。

SQL 語句

建立存儲過程前需要確定其功能,存儲過程的調用可以是無參數調用或有參數調用,可以有返回值或者沒有參數返回。建立存儲過程的命令格式是:

CREATE PROCEDURE 存儲過程名
[WITH ENCRYPTION]
[@參數名 類型 [ = 默認值][OUTPUT]][,-n ]
AS SQL語句
參數 說明
PROCEDURE 存儲過程名
WITH ENCRYPTION 將存儲過程的代碼加密
@參數名 類型 接收指定的實際參數及類型
OUTPUT 表示參數是輸出參數,若無此項則參數是輸入參數
SQL 語句 是構造存儲過程的 SQL 語句,如果包括多條命令可以用 BEGIN…END 代碼塊

調用存儲過程的方式有以下 2 種:

存儲過程名 [參數值]    --存儲過程名是批處理的第 1 條語句
EXECUTE 存儲過程名 [參數值]    --存儲過程名不是批處理的第 1 條語句

存儲過程樣例

樣例一

此時有成績表 Score 和課程表 Course,表中具有以下字段和記錄。


用戶輸入某一門課程的名稱,就可統計出該課程各分數段分布的人數。首先建立排名表:

CREATE TABLE Rank(
    division char(20),
    sub_sum int
);

INSERT INTO Rank(division) VALUES('[0,60)'),('[60,70)'),('[70,80)'),('[80,90)'),('[90,100]');

接着創建存儲過程。

CREATE PROCEDURE printcourse @pcname char(20)
AS
    DECLARE @pcno char(20), @pcount int, @count int
    set nocount on
    SELECT @count = COUNT(*) FROM Course WHERE Cname = @pcname
    IF(@count = 0)
         BEGIN
             RAISERROR('您輸入的課程不存在,請重新輸入!', 16, 1)
             RETURN
         END
    
    --查找 @pcname 對應的課程號	 
    SELECT @pcno = Score.cno FROM Course, Score WHERE Course.Cno = Score.Cno AND Course.Cname = @pcname
    --統計不及格人數,並更新 Rank 表
    SELECT @pcount = COUNT(*) FROM Score WHERE Degree < 60 AND Cno = @pcno
    UPDATE Rank SET sub_sum = @pcount WHERE division = '[0,60)'
    
    SELECT @pcount = COUNT(*) FROM Score WHERE Degree >= 60 AND Degree < 70 AND Cno = @pcno
    UPDATE Rank SET sub_sum = @pcount WHERE division = '[60,70)'

    SELECT @pcount = COUNT(*) FROM Score WHERE Degree >= 70 AND Degree < 80 AND Cno = @pcno
    UPDATE Rank SET sub_sum = @pcount WHERE division='[70,80)'

    SELECT @pcount = COUNT(*) FROM Score WHERE Degree >= 80 AND Degree < 90 AND Cno = @pcno
    UPDATE Rank SET sub_sum = @pcount WHERE division='[80,90)'

    SELECT @pcount = COUNT(*) FROM Score WHERE Degree >= 90 AND Degree <= 100 AND Cno = @pcno
    UPDATE Rank SET sub_sum = @pcount WHERE division = '[90,100]'

最后嘗試執行該存儲過程。

EXEC printcourse '計算機導論'

SELECT * FROM Rank

樣例二

統計某一門課的平均成績,存儲過程可帶有一個字符型參數值,接受用戶輸入的課程名稱。一個輸出參數(用 output 聲明)用於存放返回給調用者的這門課程的平均成績)。

CREATE PROCEDURE printavg_course @pcname char(20), @pavg int output
AS

    DECLARE @pcno char(20)
    SET NOCOUNT ON
    SELECT @count = COUNT(*) FROM Course WHERE Cname = @pcname
    IF(@count = 0)
         BEGIN
             RAISERROR('您輸入的課程不存在,請重新輸入!', 16, 1)
             RETURN
         END

         --最關鍵的 2 行
     SELECT @pcno = Score.cno FROM Course, Score WHERE Course.Cno = Score.Cno AND Course.Cname = @pcname
     SELECT @pavg = AVG(Score.Degree) FROM Score WHERE Cno = @pcno
     PRINT RTrim(@pcname) + '的平均成績為:' + CAST(@pavg AS char(5))

運行該存儲過程。

DECLARE @pavg int

EXEC printavg_course '操作系統', @pavg output

Select @pavg int

樣例三

在 Course 表中查詢學生的學號、課程號和成績,但是要將學生選課成績從百分制改為等級制,即 A、B、C、D、E 五級。

CREATE PROCEDURE printclass_degree 
AS
    SELECT Sno, Cno, Degree,
    CASE
         WHEN Degree <  60                   THEN '不及格'
         WHEN Degree >= 60 AND Degree < 70   THEN '及格'
         WHEN Degree >= 70 AND Degree < 80   THEN '中'
         WHEN Degree >= 80 AND Degree < 90   THEN '良'
         WHEN Degree >= 90 AND Degree <= 100 THEN '優'
         ELSE '成績為空!'
    END AS 'Degree  Classified'
    FROM Score

運行該存儲過程。

EXEC printclass_degree 

樣例四

表 Course 增加兩列,分別是課程選修最大人數(mn ,默認50)和當前人數(cn ,默認0)。

某學生沒有選過某課程,要選某課程且沒有超過課程最大人數時,可以選擇該課程,當前選課人數加1,並在成績 Score 表中增加對應的該生該課程的成績為 0 記錄。否則,提示該課程選課人數已滿,不能選課。

CREATE PROCEDURE cs @sno char(3), @cno char(5)
AS
	DECLARE @mn INT, @cn INT, @count INT
	SET @count = (SELECT count(Sno) FROM Score WHERE Sno = @sno AND Cno = @cno)
	IF(@count = 1)
	BEGIN
		RAISERROR('該學生已經選過這門課',16,1)
	END
	ELSE
	BEGIN
		SELECT @mn = mn FROM Course WHERE Cno = @Cno
		SET @count = (SELECT count(Sno) FROM Score WHERE Cno = @Cno)

		IF(@count >= @mn)
		BEGIN
			RAISERROR('該課程已達到最大選課人數',16,1)
		END
		ELSE
		BEGIN
			UPDATE Course SET cn = @count + 1 WHERE Cno = @cno
			INSERT INTO Score(Sno, Cno, Degree) VALUES(@sno, @cno, 0)
			RAISERROR('學生選課成功',16,1)
		END
	END

運行該存儲過程。

EXEC cs '101', '3-245'
SELECT * FROM Score
SELECT * FROM Course

EXEC cs '101', '3-235'


某學生選了某課程后要退選,該課程的當前選課人數減 1 並刪除其對應的成績。

CREATE PROCEDURE csd @sno char(3), @cno char(5)
AS
	DECLARE @mn INT, @cn INT, @count INT
	SET @count = (SELECT count(Sno) FROM Score WHERE Sno = @sno AND Cno = @cno)
	IF(@count = 0)
	BEGIN
		RAISERROR('該學生沒有選過這門課',16,1)
	END
	ELSE
	BEGIN
		SELECT @cn = cn FROM Course010 WHERE Cno = @Cno
		UPDATE Course SET cn = @cn - 1 WHERE Cno = @cno
		DELETE Score WHERE Sno = @sno AND Cno = @cno
		RAISERROR('學生退課成功',16,1)
	END

運行該存儲過程。

EXEC csd '101', '3-245'
SELECT * FROM Score
SELECT * FROM Course

EXEC csd '101', '3-245'


某學生選了某課程后,可以查詢其成績(out)。

CREATE PROCEDURE cx @sno char(3), @cno char(5)
AS
	DECLARE @mn INT, @cn INT, @count INT
	SET @count = (SELECT count(Sno) FROM Score WHERE Sno = @sno AND Cno = @cno)
	IF(@count = 0)
	BEGIN
		RAISERROR('該學生沒有選過這門課',16,1)
	END
	ELSE
	BEGIN
		SELECT * FROM Score WHERE Cno = @cno AND Sno = @sno
	END

運行該存儲過程。

EXEC cx '101', '3-245'


如果學生沒有選課,則看到如下信息。

參考資料

《SqlServer 2014 數據庫技術實用教程》,胡伏湘、肖玉朝 主編,清華大學出版社


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM