首页 > 技术文章 > 存储过程

mingqi-420 2019-04-20 11:06 原文

  1. 存储过程的类型:

(1)    用户自定义存储过程

             自定义存储过程即用户使用T_SQL语句编写的、为了实现某一特定业务需求,在用户数据库中编写的T_SQL语句集合,自定义存储过程可以接受输入参数、向客户端返回结果和信息,返回输出参数等。创建自定义存储过程时,存储过程名前加上"##"表示创建了一个全局的临时存储过程;存储过程前面加上"#"时,表示创建的局部临时存储过程。局部临时存储过程只能在创建它的回话中使用,会话结束时,将被删除。这两种存储过程都存储在tempdb数据库中。

用户定义的存储过程分为两类:T_SQL 和CLR

T_SQL:存储过程是值保存的T_SQL语句集合,可以接受和返回用户提供的参数,存储过程也可能从数据库向客户端应用程序返回数据。

 

CLR存储过程是指引用Microsoft.NET Framework公共语言的方法存储过程,可以接受和返回用户提供的参数,它们在.NET Framework程序集是作为类的公共静态方法实现的。

(2)    扩展存储过程

            扩展存储过程是以在SQL SERVER环境外执行的动态连接(DLL文件)来实现的,可以加载到SQL SERVER实例运行的地址空间中执行,扩展存储过程可以用SQL SERVER扩展存储过程API编程,扩展存储过程以前缀"xp_"来标识,对于用户来说,扩展存储过程和普通话存储过程一样,可以用相同的方法来执行。

(3)    系统存储过程

              系统存储过程是 SQL Server系统自身提供的存储过程,可以作为命令执行各种操作。

        系统存储过程主要用来从系统表中获取信息,使用系统存储过程完成数据库服务器的管理工作,为系统管理员提供帮助,为用户查看数据库对象提供方便,系统存储过程位于数据库服务器中,并且以sp_开头,系统存储过程定义在系统定义和用户定义的数据库中,在调用时不必在存储过程前加数据库限定名。例如:sp_rename系统存储过程可以修改当前数据库中用户创建对象的名称,sp_helptext存储过程可以显示规则,默认值或视图的文本信息,SQL SERVER服务器中许多的管理工作都是通过执行系统存储过程来完成的,许多系统信息也可以通过执行系统存储过程来获得。

          系统存储过程创建并存放在与系统数据库master中,一些系统存储过程只能由系统管理员使用,而有些系统存储过程通过授权可以被其它用户所使用。

2.Sql存储过程

   (1)创建存储过程

       使用 create Procedure语句来创建存储过程,存储过程名称在该语句之后,as关键字标示存储过程主体的开始,存储过程有多个sql语句组成,例如下面的语句创建一个名为usp_getAllEmployees的存储过程,用于从employeeDepartment表中检索数据

Create Procedure usp_getAllEmployees

As

  Select LastName,FirstName,JobTitle,Department

  From employeeDepartment

要执行一个存储过程,可以使用execute语句:

Execute  usp_getAllEmployees

存储过程的参数

存储过成人能够通过参数与调用程序通讯。参数定义应当出现在存储过程名称的后面,as的前面,当程序执行存储过程时,可通过存储过程的参数向该存储过程传递值,也可以output参数将值返回至调用程序

1、指定参数的名称和数据类型

参数名称应当以@开始,以后的字符可以是遵守对象标识符的任意字符,并以@@开头,因为这是用于内置函数的标识符号,例如下面创建的usp_GetProduct存储过程包含@standardCost和@listPrice两个参数,参数的数据类型均是money

Create produce usp_GetProduct

      @standardCost money,@listPrice money

As

  Select name, standardCost, listPrice from product

 Where standardCost>@ standardCost and listPrice> @listPrice

执行存储过程时,既可以通过显式的方式指定参数名称并分配适当的值,也可以直接分配参数值,如果使用了显式方式,则按任意顺序提供参数,如果未指定参数名称,则必须按参数在存储过程定义的时候的顺序来提供。

Excute usp_GetProduct @ listPrice=100,@standardCost=10

Excute usp_GetProduct 10 ,100

2、为参数指定默认值

在参数定义中可以为可选参数指定一个,默认值,执行该存储过程时,如果未指定其他值,则使用默认值

Create produce usp_GetProduct

         @standardCost money=0,@listPrice money

As

        Select name, standardCost, listPrice from product

 Where standardCost>@ standardCost and listPrice> @listPrice

执行该存储过程,可以只为@listPrice指定参数

Excute usp_GetProduct @ listPrice=100

由于具有默认参数通常是可选参数,所以建议将他们放置在参数列表的末尾以便于调用。

对于字符参数,在参数传递时可以指定通配符

3、指定输出参数

默认情况下,所有的参数均为输出参数,要指定输出参数,必须在参数定义中使用output关键字。当存储过程退出时,它将向调用程序返回输出参数的当前值。,例如,下面创建的存储过程定义了一个输出参数@productCount,用于返回ListPrice大于指定产品的数量

Create produce usp_GetProduct

                 @productCount int output,

                 @listPrice money

As

               set @productCount= (select count(id) from product

               Where  listPrice> @listPrice)

  1. 修改存储过程

如果需要修改存储过程中的语句或者参数,可以删除并重新创建该存储过程,也可以使用alter producedure语句更改该存储过程。删除并重新建时,与该存储过程关联的所有权限将丢失,更改时,将更改过程或者参数定义,但为该存储过程定义的权限将保留,将不会影响任何相关的存储过程或触发器

Alrter produce usp_GetProduct

         @standardCost money=0,@listPrice money

As

        Select name, standardCost, listPrice from product

 Where standardCost>@ standardCost and listPrice> @listPrice

  1. 存储过程的重新编译

1、指定在下次执行时重新编译

可以使用sp_recompile系统存储过程指定在下次执行存储过程或触发器进行重新编译

2、从sql server 2005开始,引入了对存储过程执行语句级重新编译的功能,也就是说在重新编译存储过程时,值编译导致重新编译的语句,而不编译整个存储过程。

要使用此功能,应当在语句中包含recomple查询提示,recomeple指示数据库引擎在执行查询后,丢弃为其生成的查询计划,从而在下次执行时强制编译查询计划,如果未指定recompile。数据库将缓存查询计划并从新使用它们

3、每次执行时重新编译村重过程

在创建存储过程时指定with recompile选项,强制在执行存储过程时对其进行重新编译,指定该选项时,数据库引擎将部位该存储过程缓存执行计划,而是在每次执行时都重新编译

      4.创建带游标参数的存储过程

if (object_id('book_cursor', 'P') is not null)

             drop proc book_cursor

go

create proc book_cursor

          @bookCursor cursor varying output

as

           set @bookCursor=cursor forward_only static for

           select book_id,book_name,book_auth from books

           open @bookCursor;

go

--调用book_cursor存储过程

declare @cur cursor,

                  @bookID int,

                  @bookName varchar(20),

                  @bookAuth varchar(20);

exec book_cursor @bookCursor=@cur output;

fetch next from @cur into @bookID,@bookName,@bookAuth;

while(@@FETCH_STATUS=0)

begin

               fetch next from @cur into @bookID,@bookName,@bookAuth;

               print 'bookID:'+convert(varchar,@bookID)+' , bookName: '+ @bookName

                +' ,bookAuth: '+@bookAuth;

end

close @cur    --关闭游标

DEALLOCATE @cur; --释放游标

5.创建分页存储过程

if (object_id('book_page', 'P') is not null)

    drop proc book_page

go

create proc book_page(

    @TableName varchar(50),            --表名

    @ReFieldsStr varchar(200) = '*',   --字段名(全部字段为*)

    @OrderString varchar(200),         --排序字段(必须!支持多字段不用加order by)

    @WhereString varchar(500) =N'',  --条件语句(不用加where)

    @PageSize int,                     --每页多少条记录

    @PageIndex int = 1 ,               --指定当前为第几页

    @TotalRecord int output            --返回总记录数

)

as

begin

     --处理开始点和结束点

    Declare @StartRecord int;

    Declare @EndRecord int;

    Declare @TotalCountSql nvarchar(500);

    Declare @SqlString nvarchar(2000);   

    set @StartRecord = (@PageIndex-1)*@PageSize + 1

    set @EndRecord = @StartRecord + @PageSize - 1

    SET @TotalCountSql= N'select @TotalRecord = count(*) from ' + @TableName;--总记录数语句

    SET @SqlString = N'(select row_number() over (order by '+ @OrderString +') as rowId,'+@ReFieldsStr+' from '+ @TableName;--查询语句

    --

    IF (@WhereString! = '' or @WhereString!=null)

        BEGIN

            SET @TotalCountSql=@TotalCountSql + '  where '+ @WhereString;

            SET @SqlString =@SqlString+ '  where '+ @WhereString;           

        END

    --第一次执行得到

    --IF(@TotalRecord is null)

    --   BEGIN

           EXEC sp_executesql @totalCountSql,N'@TotalRecord int out',@TotalRecord output;--返回总记录数

    --  END

    ----执行主语句

    set @SqlString ='select * from ' + @SqlString + ') as t where rowId between ' + ltrim(str(@StartRecord)) + ' and ' +  ltrim(str(@EndRecord));

    Exec(@SqlString)   

END

--调用分页存储过程book_page

exec book_page 'books','*','book_id','',3,1,0;

 

--

declare @totalCount int

exec book_page 'books','*','book_id','',3,1,@totalCount output;

select @totalCount as totalCount;--总记录数。

推荐阅读