zoukankan      html  css  js  c++  java
  • 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

    存储过程很多知识,暂时先写到这里。

    未完待续.........

     

     

    共同学习,共同进步!
  • 相关阅读:
    Hexo命令无法找到 -问题修复
    技术的本质
    java 多线程总结篇4——锁机制
    java 多线程总结篇3之——生命周期和线程同步
    java 多线程总结篇2之——Thread类及常用函数
    java 多线程总结篇1之——基本概念
    java IO流的继承体系和装饰类应用
    java IO流知识点总结
    java IO流之——File类知识总结和面试
    为什么需要学UML建模
  • 原文地址:https://www.cnblogs.com/lideng/p/3013966.html
Copyright © 2011-2022 走看看