1. 程式人生 > >sql server儲存過程 以及幾個常用案例

sql server儲存過程 以及幾個常用案例

Transact-SQL中的儲存過程,非常類似於Java語言中的方法,它可以重複呼叫。當儲存過程執行一次後,可以將語句快取中,這樣下次執行的時候直接使用快取中的語句。這樣就可以提高儲存過程的效能。

Ø 儲存過程的概念

    儲存過程Procedure是一組為了完成特定功能的SQL語句集合,經編譯後儲存在資料庫中,使用者通過指定儲存過程的名稱並給出引數來執行。

    儲存過程中可以包含邏輯控制語句和資料操縱語句,它可以接受引數、輸出引數、返回單個或多個結果集以及返回值。

    由於儲存過程在建立時即在資料庫伺服器上進行了編譯並存儲在資料庫中,所以儲存過程執行要比單個的SQL語句塊要快。同時由於在呼叫時只需用提供儲存過程名和必要的引數資訊,所以在一定程度上也可以減少網路流量、簡單網路負擔。

    1、 儲存過程的優點

        A、 儲存過程允許標準組件式程式設計

        儲存過程建立後可以在程式中被多次呼叫執行,而不必重新編寫該儲存過程的SQL語句。而且資料庫專業人員可以隨時對儲存過程進行修改,但對應用程式原始碼卻毫無影響,從而極大的提高了程式的可移植性。

        B、 儲存過程能夠實現較快的執行速度

        如果某一操作包含大量的T-SQL語句程式碼,分別被多次執行,那麼儲存過程要比批處理的執行速度快得多。因為儲存過程是預編譯的,在首次執行一個儲存過程時,查詢優化器對其進行分析、優化,並給出最終被存在系統表中的儲存計劃。而批處理的T-SQL語句每次執行都需要預編譯和優化,所以速度就要慢一些。

        C、 儲存過程減輕網路流量

        對於同一個針對資料庫物件的操作,如果這一操作所涉及到的T-SQL語句被組織成一儲存過程,那麼當在客戶機上呼叫該儲存過程時,網路中傳遞的只是該呼叫語句,否則將會是多條SQL語句。從而減輕了網路流量,降低了網路負載。

        D、 儲存過程可被作為一種安全機制來充分利用

        系統管理員可以對執行的某一個儲存過程進行許可權限制,從而能夠實現對某些資料訪問的限制,避免非授權使用者對資料的訪問,保證資料的安全。

Ø 系統儲存過程

    系統儲存過程是系統建立的儲存過程,目的在於能夠方便的從系統表中查詢資訊或完成與更新資料庫表相關的管理任務或其他的系統管理任務。系統儲存過程主要儲存在master資料庫中,以“sp”下劃線開頭的儲存過程。儘管這些系統儲存過程在master資料庫中,但我們在其他資料庫還是可以呼叫系統儲存過程。有一些系統儲存過程會在建立新的資料庫的時候被自動建立在當前資料庫中。

    常用系統儲存過程有:

exec sp_databases; --檢視資料庫
exec sp_tables;        --查看錶
exec sp_columns student;--檢視列
exec sp_helpIndex student;--檢視索引
exec sp_helpConstraint student;--約束
exec sp_stored_procedures;
exec sp_helptext 'sp_stored_procedures';--檢視儲存過程建立、定義語句
exec sp_rename student, stuInfo;--修改表、索引、列的名稱
exec sp_renamedb myTempDB, myDB;--更改資料庫名稱
exec sp_defaultdb 'master', 'myDB';--更改登入名的預設資料庫
exec sp_helpdb;--資料庫幫助,查詢資料庫資訊
exec sp_helpdb master;

    系統儲存過程示例:
--表重新命名
exec sp_rename 'stu', 'stud';
select * from stud;
--列重新命名
exec sp_rename 'stud.name', 'sName', 'column';
exec sp_help 'stud';
--重新命名索引
exec sp_rename N'student.idx_cid', N'idx_cidd', N'index';
exec sp_help 'student';

--查詢所有儲存過程
select * from sys.objects where type = 'P';
select * from sys.objects where type_desc like '%pro%' and name like 'sp%';

Ø 使用者自定義儲存過程

   1、 建立語法

create proc | procedure pro_name
    [{@引數資料型別} [=預設值] [output],
     {@引數資料型別} [=預設值] [output],
     ....
    ]
as
    SQL_statements

   2、 建立不帶引數儲存過程

--建立儲存過程
if (exists (select * from sys.objects where name = 'proc_get_student'))
    drop proc proc_get_student
go
create proc proc_get_student
as
    select * from student;

--呼叫、執行儲存過程
exec proc_get_student;

   3、 修改儲存過程

--修改儲存過程
alter proc proc_get_student
as
select * from student;

   4、 帶參儲存過程

--帶參儲存過程
if (object_id('proc_find_stu', 'P') is not null)
    drop proc proc_find_stu
go
create proc proc_find_stu(@startId int, @endId int)
as
    select * from student where id between @startId and @endId
go

exec proc_find_stu 2, 4;

   5、 帶萬用字元引數儲存過程

--帶萬用字元引數儲存過程
if (object_id('proc_findStudentByName', 'P') is not null)
    drop proc proc_findStudentByName
go
create proc proc_findStudentByName(@name varchar(20) = '%j%', @nextName varchar(20) = '%')
as
    select * from student where name like @name and name like @nextName;
go

exec proc_findStudentByName;
exec proc_findStudentByName '%o%', 't%';

   6、 帶輸出引數儲存過程

if (object_id('proc_getStudentRecord', 'P') is not null)
    drop proc proc_getStudentRecord
go
create proc proc_getStudentRecord(
    @id int, --預設輸入引數
    @name varchar(20) out, --輸出引數
    @age varchar(20) output--輸入輸出引數
)
as
    select @name = name, @age = age  from student where id = @id and sex = @age;
go

-- 
declare @id int,
        @name varchar(20),
        @temp varchar(20);
set @id = 7; 
set @temp = 1;
exec proc_getStudentRecord @id, @name out, @temp output;
select @name, @temp;
print @name + '#' + @temp;

   7、 不快取儲存過程

--WITH RECOMPILE 不快取
if (object_id('proc_temp', 'P') is not null)
    drop proc proc_temp
go
create proc proc_temp
with recompile
as
    select * from student;
go

exec proc_temp;

   8、 加密儲存過程

--加密WITH ENCRYPTION 
if (object_id('proc_temp_encryption', 'P') is not null)
    drop proc proc_temp_encryption
go
create proc proc_temp_encryption
with encryption
as
    select * from student;
go

exec proc_temp_encryption;
exec sp_helptext 'proc_temp';
exec sp_helptext 'proc_temp_encryption';

   9、 帶遊標引數儲存過程

if (object_id('proc_cursor', 'P') is not null)
    drop proc proc_cursor
go
create proc proc_cursor
    @cur cursor varying output
as
    set @cur = cursor forward_only static for
    select id, name, age from student;
    open @cur;
go
--呼叫
declare @exec_cur cursor;
declare @id int,
        @name varchar(20),
        @age int;
exec proc_cursor @cur = @exec_cur output;--呼叫儲存過程
fetch next from @exec_cur into @id, @name, @age;
while (@@fetch_status = 0)
begin
    fetch next from @exec_cur into @id, @name, @age;
    print 'id: ' + convert(varchar, @id) + ', name: ' + @name + ', age: ' + convert(char, @age);
end
close @exec_cur;
deallocate @exec_cur;--刪除遊標

   10、 分頁儲存過程

---儲存過程、row_number完成分頁
if (object_id('pro_page', 'P') is not null)
    drop proc proc_cursor
go
create proc pro_page
    @startIndex int,
    @endIndex int
as
    select count(*) from product
;    
    select * from (
        select row_number() over(order by pid) as rowId, * from product 
    ) temp
    where temp.rowId between @startIndex and @endIndex
go
--drop proc pro_page
exec pro_page 1, 4
--
--分頁儲存過程
if (object_id('pro_page', 'P') is not null)
    drop proc pro_stu
go
create procedure pro_stu(
    @pageIndex int,
    @pageSize int
)
as
    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 number from student 
    ) t
    where t.number between @startRow and @endRow;

exec pro_stu 2, 2;

Ø Raiserror

Raiserror返回使用者定義的錯誤資訊,可以指定嚴重級別,設定系統變數記錄所發生的錯誤。

   語法如下:

Raiserror({msg_id | msg_str | @local_variable}
  {, severity, state}
  [,argument[,…n]]
  [with option[,…n]]
)

   # msg_id:在sysmessages系統表中指定的使用者定義錯誤資訊

   # msg_str:使用者定義的資訊,資訊最大長度在2047個字元。

   # severity:使用者定義與該訊息關聯的嚴重級別。當使用msg_id引發使用sp_addmessage建立的使用者定義訊息時,raiserror上指定嚴重性將覆蓋sp_addmessage中定義的嚴重性。

    任何使用者可以指定0-18直接的嚴重級別。只有sysadmin固定伺服器角色常用或具有alter trace許可權的使用者才能指定19-25直接的嚴重級別。19-25之間的安全級別需要使用with log選項。

   # state:介於1至127直接的任何整數。State預設值是1。

raiserror('is error', 16, 1);
select * from sys.messages;
--使用sysmessages中定義的訊息
raiserror(33003, 16, 1);
raiserror(33006, 16, 1);






導讀:sql儲存是資料庫操作過程中比較重要的一個環節,對於一些初學者來說也是比較抽象難理解的,本文我將通過幾個例項來解析資料庫中的sql儲存過程,這樣就將抽象的事物形象化,比較容易理解。

例1:

create proc proc_stu
@sname varchar(20),
@pwd varchar(20)
as
select * from ren where [email protected] and [email protected]
go

檢視結果:proc_stu 'admin','admin'

例2:

下面的儲存過程實現使用者驗證的功能,如果不成功,返回0,成功則返回1.

CREATE PROCEDURE VALIDATE @USERNAME CHAR(20),@PASSWORD CHAR(20),@LEGAL BIT OUTPUT
AS

IF EXISTS(SELECT * FROM REN WHERE SNAME = @USERNAME AND PWD = @PASSWORD)
SELECT @LEGAL = 1
ELSE
SELECT @LEGAL = 0

在程式中呼叫該儲存過程,並根據@LEGAL引數的值判斷使用者是否合法。

例3:一個高效的資料分頁的儲存過程 可以輕鬆應付百萬資料

CREATE PROCEDURE pageTest --用於翻頁的測試
--需要把排序欄位放在第一列

(
@FirstID nvarchar(20)=null, --當前頁面裡的第一條記錄的排序欄位的值
@LastID nvarchar(20)=null, --當前頁面裡的最後一條記錄的排序欄位的值
@isNext bit=null, --true 1 :下一頁;false 0:上一頁
@allCount int output, --返回總記錄數
@pageSize int output, --返回一頁的記錄數
@CurPage int --頁號(第幾頁)0:第一頁;-1最後一頁。
)

AS

if @CurPage=0--表示第一頁
begin
--統計總記錄數
select @allCount=count(ProductId) from Product_test

set @pageSize=10
--返回第一頁的資料
select top 10
ProductId,
ProductName,
Introduction
from Product_test order by ProductId
end

else if @CurPage=-1--表示最後一頁

select * from
(select top 10 ProductId,
ProductName,
Introduction

from Product_test order by ProductId desc ) as aa
order by ProductId
else

begin
if @isNext=1
--翻到下一頁
select top 10 ProductId,
ProductName,
Introduction
from Product_test where ProductId > @LastID order by ProductId
else
--翻到上一頁
select * from
(select top 10 ProductId,
ProductName,
Introduction
from Product_test where ProductId < @FirstID order by ProductId desc) as bb order by ProductId
end

上文中講到的這三個例子都是sql儲存過程比較典型的例子,希望大家好好學習,都能夠學到大家各自需要的東西。

分頁

程式碼如下: /*分頁查詢資料*/ CREATE PROCEDURE [dbo].[GetRecordSet] @strSql varchar(8000),--查詢sql,如select * from [user] @PageIndex int,--查詢當頁號 @PageSize int--每頁顯示記錄 AS set nocount on declare @p1 int declare @currentPage int set @currentPage = 0 declare @RowCount int set @RowCount = 0 declare @PageCount int set @PageCount = 0 exec sp_cursoropen @p1 output,@strSql,@scrollopt=1,@ccopt=1,@[email protected] output --得到總記錄數 select @PageCount=ceiling(1.0*@rowCount/@pagesize) --得到總頁數 ,@currentPage=(@PageIndex-1)*@PageSize+1 select @RowCount,@PageCount exec sp_cursorfetch @p1,16,@currentPage,@PageSize exec sp_cursorclose @p1 set nocount off GO 使用者註冊: /* 使用者註冊,也算是新增吧 */ Create proc [dbo].[UserAdd] ( @loginID nvarchar(50),     --登入帳號 @password nvarchar(50), --密碼 @email nvarchar(200) --電子信箱 ) as declare @userID int --使用者編號 --登入賬號已經被註冊 if exists(select loginID from tableName where loginID = @loginID) begin return -1; end --郵箱已經被註冊 else if exists(select email from tableName where email = @email) begin return -2; end --註冊成功 else begin select @userID = isnull(max(userID),100000)+1 from tableName insert into tableName (userID,loginID,[password],userName,linkNum,address,email,createTime,status) values (@userID,@loginID,@password,'','','',@email,getdate(),1) return @userID end SQL Server 系統儲存過程 1. 給表中欄位新增描述資訊 Create table T2 (id int , name char (20)) GO EXEC sp_addextendedproperty 'MS_Description', 'Employee ID', 'user', dbo, 'table', T2, 'column', id EXEC sp_updateextendedproperty 'MS_Description', 'this is a test', 'user', dbo, 'table', T2, 'column', id 2.修改資料庫名稱 EXEC sp_renamedb 'old_db_name', 'new_db_name' 3.修改資料表名稱和欄位名稱 EXEC sp_rename 'old_table_name', 'new_table_name'–修改資料表名稱 EXEC sp_rename 'table_name.[old_column_name]', 'new_column_name', 'COLUMN'–修改欄位名稱 4.給定儲存過程名,獲取儲存過程內容 exec sp_helptext sp_name 以下是關於資料庫控制的 *以下是有關安全控制的系統儲存過程或 SQL 語句,詳細語法查閱《聯機叢書》相關內容*/ –建立新的 SQL Server 登入,使使用者得以連線使用 SQL Server 身份驗證的 SQL Server。 EXEC sp_addlogin @loginame = '', @passwd = '', @defdb = '', @deflanguage = NULL, @sid = NULL, @encryptopt = NULL –使 Windows NT 使用者或組帳戶得以使用 Windows 身份驗證連線到 SQL Server。 EXEC sp_grantlogin @loginame = '' –刪除 SQL Server 登入,以阻止使用該登入名訪問 SQL Server。 EXEC sp_droplogin @loginame = '' –阻止 Windows NT 使用者或組連線到 SQL Server。 EXEC sp_denylogin @loginame = '' –從 SQL Server 中刪除用 sp_grantlogin 或 sp_denylogin 建立的 Windows NT 使用者或組的登入項。 EXEC sp_revokelogin @loginame = '' –更改登入的預設資料庫。 EXEC sp_defaultdb @loginame = '', @defdb = '' –更改登入的預設語言。 EXEC sp_defaultlanguage @loginame = '', @language = '' –新增或更改 SQL Server 登入密碼。 EXEC sp_password @old = '', @new = '', @loginame = '' –新增伺服器角色新成員。 EXEC sp_addsrvrolemember @loginame = '', @rolename = '' –新增伺服器角色某成員。 EXEC sp_dropsrvrolemember @loginame = '' , @rolename = '' –為 SQL Server 登入或 Windows NT 使用者或組在當前資料庫中新增一個安全帳戶,並使其能夠被授予在資料庫中執行活動的許可權(授予預設的“public”資料庫角色)。 EXEC sp_grantdbaccess @loginame = '', @name_in_db = NULL –或 EXEC sp_adduser @loginame = '', @name_in_db = NULL, @grpname = '' –從當前資料庫中刪除安全帳戶。 EXEC sp_revokedbaccess @name_in_db = '' –或 EXEC sp_dropuser @name_in_db = '' –在當前資料庫建立新資料庫角色。 EXEC sp_addrole @rolename = '', @ownername = '' –在當前資料庫刪除某資料庫角色。 EXEC sp_droprole @rolename = '' –在當前資料庫中新增資料庫角色新成員。 EXEC sp_addrolemember @rolename = '', @membername = '' –在當前資料庫中刪除資料庫角色某成員。 EXEC sp_droprolemember @rolename = '', @membername = '' –許可權分配給資料庫角色、表、儲存過程等物件 –1、授權訪問 GRANT –2、拒絕訪問 DENY –3、取消授權或拒絕 REVOKE –4、Sample(pubs): GRANT SELECT ON authors TO Limperator DENY SELECT ON authors TO Limperator REVOKE SELECT ON authors TO Limperator