SQL 存儲過程入門(基礎知識)(一)


大學里面對存儲過程沒有講到什么,工作了一段時間,對存儲過程還是沒有用到,根本不需要去寫存儲過程,可能是做的軟件方向的原因吧。為了以后發展,決定從零開始學習下。

 

 一,基礎知識  http://www.cnblogs.com/lideng/archive/2013/04/11/3013966.html

 二,變量使用  http://www.cnblogs.com/lideng/archive/2013/04/11/3014407.html

 三,流程控制語句 http://www.cnblogs.com/lideng/archive/2013/04/12/3016583.html

 四,事務的使用   http://www.cnblogs.com/lideng/archive/2013/04/13/3017804.html

 五,小結          http://www.cnblogs.com/lideng/p/3168513.html

 

 

這里看看存儲過程的定義,

存儲過程(Stored Procedure),是一組為了完成特定功能的SQL 語句,集經編譯后存儲在數據庫中,用戶通過指定存儲過程的名字並給出參數,如果該存儲過程帶有參數來執行。

在SQL Server 的系列版本中,存儲過程分為兩類:系統提供的存儲過程和用戶自定義存儲過程。

  系統SP,主要存儲master 數據庫中,並以sp_為前綴並且系統存儲過程主要是從系統表中獲取信息,從而為系統管理員管理SQL Server。

    常用系統存儲過程有:
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';--查看存儲過程創建、定義語句 經常用到這句話來查看存儲過程,like sp_helptext sp_getLoginInfo.
exec sp_rename student, stuInfo;--修改表、索引、列的名稱
exec sp_renamedb myTempDB, myDB;--更改數據庫名稱
exec sp_defaultdb 'master', 'myDB';--更改登錄名的默認數據庫
exec sp_helpdb;--數據庫幫助,查詢數據庫信息
exec sp_helpdb master;

 

    用戶自定義存儲過程是由用戶創建,並能完成某一特定功能,如:查詢用戶所需數據信息的存儲過程。

這里我們看看存儲過程的好處;

        (1)重復使用。存儲過程可以重復使用,從而可以減少數據庫開發人員的工作量。

        (2)提高性能。存儲過程在創建的時候就進行了編譯,將來使用的時候不用再重新編譯。一般的SQL語句每執行一次就需要編譯一次,所以使用存儲過程提高了效率。

        (3)減少網絡流量。存儲過程位於服務器上,調用的時候只需要傳遞存儲過程的名稱以及參數就可以了,因此降低了網絡傳輸的數據量。

        (4)安全性。參數化的存儲過程可以防止SQL注入式的攻擊,而且可以將Grant、Deny以及Revoke權限應用於存儲過程。

 

   好了,我們來看看創建的基本語法

 

    定義存儲過程的語法

    CREATE  PROC[EDURE]  存儲過程名

              @參數1  數據類型 = 默認值,

               …… ,

              @參數n  數據類型 OUTPUT

            AS

            SQL語句

    GO

1,參數是可選的
2,參數分為輸入參數、輸出參數
3,輸入參數允許有默認值
這里來創建一個簡單的存儲過程
CREATE PROCEDURE UserLogin @name varchar(20), @password varchar(20) AS -- 定義一個臨時用來保存密碼的變量 --DECLARE @strPwd NVARCHAR(20) 這里先不介紹變量。稍后的文章會詳細講到 BEGIN select * from userinfo where userName=@name and userPass=@password END GO 首先我們用簡單的sql查詢 select * from userinfo where userName='admin' 查詢結果: --------------------- UserName UserPass Admin Admin 現在我們來執行我們的存儲過程 exec UserLogin admin,admin --或這樣調用: EXEC UserLogin @name='admin',@password='admin' 查詢結果: --------------------- UserName UserPass Admin Admin

 

 來看一個比較完整的例子。詳細講解在后面事務的章節中。

 

USE [StoreTest]
GO
create Procedure [dbo].[P_InsertUser] @UserName varchar(100), @UserPwd varchar(100) AS Begin Set NOCOUNT ON; Set XACT_ABORT ON; --這句話非常重要 Begin try if(isnull(@UserName,'')='')
   begin
print 'UserName is empty';
     return ;
end
declare @iCount int; set @iCount = 0; select @iCount = Count(1) from userinfo with(nolock) where username=@UserName; if( @iCount > 0 ) begin print 'the current name already exist'; return end Begin Tran --開始事務,事務中不能有return語句 --insert insert into userinfo( username ,userpwd ,RegisterTime ) values( @UserName, @UserPwd, getdate() ) Commit Tran --提交事務 end try begin catch --在此可以使用xact_state()來判斷是否有不可提交的事務,不可提交的事務 --表示在事務內部發生錯誤了。Xact_state()有三種值:-1.事務不可提交; --1.事務可提交;0.表示沒有事務,此時commit或者rollback會報錯。 if xact_state()=-1 begin rollback tran; --事務回滾 SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_MESSAGE() AS ErrorMessage; end end catch Set XACT_ABORT off; End --調用存儲過程 exec [P_InsertUser] '','admin' --插入失敗的 GO

 

  

 

 


注意,在SQL SERVER中,所有用戶定義的變量都以“@”開頭,OUTPUT關鍵字表示這個參數是用來輸出的,AS之后就是存儲過程內容了。只要將以上代碼在“查詢分析器”里執行一次,SQL SERVER就會在當前數據庫中創建一個名為“UserLogin”的存儲過程。你可以打開“企業管理器”,選擇當前操作的數據庫,然后在左邊的樹型列表中選擇"可編程性->存儲過程",此時就可以在右邊的列表中看到你剛剛創建的存儲過程了(如果沒有,刷新一下即可)。

看到了在數據中調用存儲過程的方法有兩種(這里EXEC與EXECUTE等效);

      EXEC  過程名  參數值1,參數值2,....

或者 

 EXEC 參數1=參數值1,參數2=參數值2....

上面我們也看到了。

 如果要刪除一個存儲過程,用drop

像這樣

DROP PROCEDURE UserLogin

 

 

創建這樣的存儲過程有什么用呢,不是只能在數據中查看賽。

我們在做web或者winform 程序,假設需要個登錄,好,我們可以調用用這個存儲過程來登錄,根據傳入的參數,如果查詢出來有記錄,那么這條記錄在數據庫中存在,表示登錄成功,否則失敗。比如在報表顯示的時候,涉及到比較復雜的計算,可以再存儲過程中完成。

這樣做的目的更加安全,可以防止sql注入。

什么是sql注入呢,這里我就不多說了。請查看 ,http://baike.baidu.com/view/3896.htm

 

這里分享一個比較通用的分頁存儲過程。測試通過。

Use TaskTest
GO

IF EXISTS (SELECT 1 FROM DBO.SYSOBJECTS WHERE NAME = 'PageIndex' AND TYPE = 'P')
BEGIN
    DROP PROCEDURE PageIndex
    print @@Servername + '-' +convert(varchar,getdate(),121) + '###' + DB_Name() + '.dbo.PageIndex dropped' 
END
GO

CREATE PROCEDURE PageIndex
@tblName varchar(255), --table Name
@PageSize int = 10, --each page size
@PageIndex int = 1, --page index
@strGetFields varchar(1000) = '*', --get which column names.
@OrderType varchar(20) = 0,--default is asc,0 means ASC, 1 means desc
@fldName varchar(100), --order by which field.
@strWhere varchar(1500) = '' --no need add 'where'
AS
declare @strSQL varchar(5000);
declare @strTmp varchar(110) ;
declare @strOrder varchar(400) ;

if (@OrderType != 0) --not asc
begin
    set @strTmp = '<(select min ';
    set @strOrder = ' order by [' + @fldName +'] desc' ;
end;
else
begin
    set @strTmp = '>(select max ';
    set @strOrder = ' order by [' + @fldName +'] asc' ;
end;

if (@PageIndex = 1)
begin
    if(@strWhere != '' and @strWhere is not null) --has condition
        set @strSQL = 'select top ' +str(@PageSize)+ ' ' +@strGetFields+ ' from [' + @tblName + '] where ' + @strWhere + ' ' + @strOrder 
    else
        set @strSQL = 'select top ' +str(@PageSize)+' ' +@strGetFields+ ' from [' +@tblName+ '] ' +@strOrder     
end;
else
begin

    if(@strWhere != '' and @strWhere is not null) --has condition
        set @strSQL ='select top ' +str(@PageSize)+ ' ' +@strGetFields+ ' from [' +@tblName+ '] where [' +@fldName+ ']' +@strTmp+ '([' +@fldName+ ']) from (select top ' +str((@PageIndex-1)*@PageSize) + ' [' +@fldName+ '] from [' +@tblName+ '] where ' +@strWhere+ ' ' +@strOrder+ ') as tblTmp) and ' +@strWhere+ ' ' +@strOrder 
    else
        set @strSQL = 'select top ' +str(@PageSize)+ ' ' +@strGetFields+ ' from [' +@tblName+ '] where [' +@fldName+ ']' +@strTmp+ '([' +@fldName+ ']) from (select top ' +str((@PageIndex-1)*@PageSize)+ ' [' +@fldName+ '] from [' +@tblName+ ']' +@strOrder+ ') as tblTmp)' +@strOrder ;
end;

exec (@strSQL);

print @strSQL;
go

print @@Servername + '-' +convert(varchar,getdate(),121) + '###' + DB_Name() + '.dbo.PageIndex Created' 
GO
View Code

 

測試代碼:

exec PageIndex 'comment',10,3,'*',0,'replyTime','TaskID = 50'

table就自己建立了,測試通過。

 

下面這個大同小異,只是添加了返回記錄總數,和頁數目(需要處理下)

Use TaskTest
GO

IF EXISTS (SELECT 1 FROM DBO.SYSOBJECTS WHERE NAME = 'PageIndex' AND TYPE = 'P')
BEGIN
    DROP PROCEDURE PageIndex
    print @@Servername + '-' +convert(varchar,getdate(),121) + '###' + DB_Name() + '.dbo.PageIndex dropped' 
END
GO

CREATE PROCEDURE PageIndex
@tblName varchar(255), --table Name
@PageSize int = 10, --each page size
@PageIndex int = 1, --page index
@pageCount int =1 output, --return page count
@doCount int = 0 output, -- return records count
@strGetFields varchar(1000) = '*', --get which column names.
@OrderType varchar(20) = 0,--default is asc,0 means ASC, 1 means desc
@fldName varchar(100), --order by which field.
@strWhere varchar(1500) = '' --no need add 'where'
AS
declare @strSQL varchar(5000);
declare @strTmp varchar(110) ;
declare @strOrder varchar(400) ;
declare @strCount nvarchar(320);
declare @counts int ;
--get all records cout.
if(@strWhere != '' and @strWhere is not null) --has condition
begin
    set @strCount='select @counts = count(1)  from [' + @tblName + '] where ' + @strWhere + '';
end;
else
begin
    set @strCount='select @counts = count(1)  from [' + @tblName + '] ';
end;
exec sp_executesql @strCount,N'@counts int output',  @counts output;

if( @counts > 0 )
begin
    set @doCount = @counts;
    set @pageCount = @doCount / @PageSize;
end
print @pageCount;

if (@OrderType != 0) --not asc
begin
    set @strTmp = '<(select min ';
    set @strOrder = ' order by [' + @fldName +'] desc' ;
end;
else
begin
    set @strTmp = '>(select max ';
    set @strOrder = ' order by [' + @fldName +'] asc' ;
end;

if (@PageIndex = 1)
begin
    if(@strWhere != '' and @strWhere is not null) --has condition
        set @strSQL = 'select top ' +str(@PageSize)+ ' ' +@strGetFields+ ' from [' + @tblName + '] where ' + @strWhere + ' ' + @strOrder 
    else
        set @strSQL = 'select top ' +str(@PageSize)+' ' +@strGetFields+ ' from [' +@tblName+ '] ' +@strOrder     
end;
else
begin

    if(@strWhere != '' and @strWhere is not null) --has condition
        set @strSQL ='select top ' +str(@PageSize)+ ' ' +@strGetFields+ ' from [' +@tblName+ '] where [' +@fldName+ ']' +@strTmp+ '([' +@fldName+ ']) from (select top ' +str((@PageIndex-1)*@PageSize) + ' [' +@fldName+ '] from [' +@tblName+ '] where ' +@strWhere+ ' ' +@strOrder+ ') as tblTmp) and ' +@strWhere+ ' ' +@strOrder 
    else
        set @strSQL = 'select top ' +str(@PageSize)+ ' ' +@strGetFields+ ' from [' +@tblName+ '] where [' +@fldName+ ']' +@strTmp+ '([' +@fldName+ ']) from (select top ' +str((@PageIndex-1)*@PageSize)+ ' [' +@fldName+ '] from [' +@tblName+ ']' +@strOrder+ ') as tblTmp)' +@strOrder ;
end;

exec (@strSQL);

print @strSQL;
go

print @@Servername + '-' +convert(varchar,getdate(),121) + '###' + DB_Name() + '.dbo.PageIndex Created' 
GO
View Code

 

存儲過程很多知識,暫時先寫到這里。

未完待續.........

 

 

 


免責聲明!

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



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