https://www.cnblogs.com/cxm12-/p/7072012.html

https://blog.csdn.net/hj7jay/article/details/54015770

【存储过程的概念】

存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集。经编译后存储在数据库中。

存储过程是数据库中的一个重要对象,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。

存储过程是由 流控制 和 SQL语句书写的过程,这个过程经编译和优化后存储在数据库服务器中。

存储过程 可由应用程序通过一个调用来执行,而且允许用户声明变量。

同时,存储过程可以接收和输出参数、返回执行存储过程的状态值,也可以嵌套调用。

【存储过程的功能】

这类语言主要提供以下功能,让用户可以设计出符合引用需求的程序:

① 变量说明

② ANSI兼容的SQL命令(如Select,Update….)

③ 一般流程控制命令(if…else…、while….)

④ 内部函数

【存储过程的优点】

① 存储过程的能力大大增强了SQL语言的功能和灵活性。

存储过程可以用流控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的 运算。

② 可保证数据的安全性和完整性。

理由1:通过存储过程可以使没有权限的用户在控制之下间接地存取数据库,从而保证数据的安全。

理由2:通过存储过程可以使相关的动作在一起发生,从而可以维护数据库的完整性。

③ 在运行存储过程前,数据库已对其进行了语法和句法分析,并给出了优化执行方案。

这种已经编译好的过程可极大地改善SQL语句的性能。

由于执行SQL语句的大部分工作已经完成,所以存储过程能以极快的速度执行。

④ 可以降低网络的通信量。

理由:客户端调用存储过程只需要传存储过程名和相关参数即可,与传输SQL语句相比自然数据量少了很多。

⑤ 使体现企业规则的运算程序放入数据库服务器中,以便:

1). 集中控制。

2). 当企业规则发生变化时在服务器中改变存储过程即可,无须修改任何应用程序。

企业规则的特点是要经常变化,如果把体现企业规则的运算程序放入应用程序中,则当企业规则发生变化时,就需要修改应用程序工作量非常之大(修改、发行和安装应用程序)。

如果把体现企业规则的运算放入存储过程中,则当企业规则发生变化时,只要修改存储过程就可以了,应用程序无须任何变化。

【存储过程优点概括】

① 存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。

② 当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。

③ 存储过程可以重复使用,可减少数据库开发人员的工作量。

④ 安全性高,可设定只有某些用户才具有对指定存储过程的使用权

【存储过程缺点】

① 调试麻烦,但是用 PL/SQL Developer 调试很方便!弥补这个缺点。

② 移植问题,数据库端代码当然是与数据库相关的。但是如果是做工程型项目,基本不存在移植问题。

③ 重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置成运行时刻自动编译)。

④ 如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。

【存储过程的种类】

① 系统存储过程:以sp_开头,用来进行系统的各项设定.取得信息.相关管理工作。

② 本地存储过程:用户创建的存储过程是由用户创建并完成某一特定功能的存储过程,事实上一般所说的存储过程就是指本地存储过程。

③ 临时存储过程:分为两种存储过程:

一是本地临时存储过程,以井字号(#)作为其名称的第一个字符,则该存储过程将成为一个存放在tempdb数据库中的本地临时存储过程,且只有创建它的用户才能执行它;

二是全局临时存储过程,以两个井字号(##)号开始,则该存储过程将成为一个存储在tempdb数据库中的全局临时存储过程,全局临时存储过程一旦创建,以后连接到服务器的任意用户都可以执行它,而且不需要特定的权限。

④ 远程存储过程:在SQL Server2005中,远程存储过程(Remote Stored Procedures)是位于远程服务器上的存储过程,通常可以使用分布式查询和EXECUTE命令执行一个远程存储过程。

⑤ 扩展存储过程:扩展存储过程(Extended Stored Procedures)是用户可以使用外部程序语言编写的存储过程,而且扩展存储过程的名称通常以xp_开头。

系统存储过程
我们先来看一下系统存储过程,系统存储过程由系统定义,主要存放在MASTER数据库中,名称以"SP"开头或以"XP"开头。尽管这些系统存储过程在MASTER数据库中,但我们在其他数据库还是可以调用系统存储过程。有一些系统存储过程会在创建新的数据库的时候被自动创建在当前数据库中。 www.2cto.com
常用系统存储过程有:
exec sp_databases; --查看数据库
exec sp_tables; --查看表
exec sp_columns student;--查看列
exec sp_helpIndex student;--查看索引
exec sp_helpConstraint student;--约束
exec sp_helptext 'sp_stored_procedures';--查看存储过程创建定义的语句
exec 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_attach_db --附加数据库
exec sp_detach_db --分离数据库
来看一下具体的代码:

exec sp_databases
--查看有哪些数据库
use MySchool
exec sp_tables
--可以看TABLE_OWNER字段显示DBO里确认是用户自己
exec sp_columns student
--除了用系统视图可以查看列,用系统存储过程也可以查看到列
exec sp_helpindex student
--查看索引,可以看到索引的描述,经过测试发现主键也是索种的一种
exec sp_helpconstraint student
--查看约束

exec sp_helptext 'sys.all_columns'
--查看系统视图
exec sp_helptext 'sp_test'
--查看用户自定义的存储过程
exec sp_stored_procedures
--查看全部的存储过程

exec sp_rename 'student','stuInfo'
--更改表名
use master
exec sp_renamedb 'myschool','school'
--更改数据库名,为了更改成功,不能使用当前数据库,需切换到其他数据库
exec sp_rename N'student.idx_cid', N'idx_cidd', N'index';
--重命名索引
exec sp_helpdb
--数据库帮助,查询数据库信息

--分离数据库
use myschool
exec sp_detach_db 'test';
--exec sp_attach_db --附加数据库
EXEC sp_attach_db @dbname = 'test',
@filename1 = 'D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\test.mdf',
@filename2 = 'D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\test_log.ldf'
www.2cto.com
  用户自定义存储过程
在创建一个存储过程前,先来说一下存储过程的命名,看到好几篇讲存储过程的文章都喜欢在创建存储过程的时候加一个前缀,养成在存储过程名前加前缀的习惯很重要,虽然这只是一件很小的事情,但是往往小细节决定大成败。看到有的人喜欢这样加前缀,例如proc_名字。也看到这加样前缀usp_名字。前一种proc是procedure的简写,后一种sup意思是user procedure。我比较喜欢第一种,那么下面所有的存储过程名都以第一种来写。至于名字的写法采用骆驼命名法。
创建存储过程的语法如下:
CREATE PROC[EDURE] 存储过程名
@参数1 [数据类型]=[默认值] [OUTPUT]
@参数2 [数据类型]=[默认值] [OUTPUT]
AS
SQL语句
EXEC 过程名[参数]

来看一下各种不同的存储过程的实例:
45
--创建不带参数的存储过程
create procedure pro_student
as
select * from student;
--执行不带参数的存储过程
exec pro_student;

--修改不带参数的存储过程
alter procedure pro_student
as
select * from student where sid>3;
--执行修改后的存储过程
exec pro_student;

--删除存储过程
drop procedure pro_student;

--创建带输出参数的存储过程
create proc proc_getStudentRecord
(
@sex varchar(2) out, --输出参数
@age int output--输入输出参数
) www.2cto.com
as
select * from student where ssex = @sex and sage = @age;

--不缓存在存储过程
use myschool;
create procedure proc_recompileStudent
with recompile
as
select * from student

exec proc_recompileStudent

--加密的存储过程
create procedure proc_encrptStudent
with encryption
as
select * from student;

exec proc_recompileStudent
  
存储过程返回值的方式
1、返回数字类型的存储过程(还没有想到返回字符串的方法)

IF exists(select * from sys.objects where name='proc_getScore0')
drop procedure proc_getScore0
GO
create procedure proc_getScore0
(
@id int
)
AS
BEGIN
declare @score int
select @score=english from Score where id=@id

IF(@score>60) 
    return 0 
ELSE 
    return 1 

END

--测试调用返回数字的存储过程
declare @t int
EXEC @t = proc_getScore0 2
select @t;

  2、返回变量的存储过程

IF exists(select * from sys.objects where name='proc_getScore')
drop procedure proc_getScore
GO www.2cto.com
CREATE PROCEDURE proc_getScore
@id int,
@result varchar(50) output
AS
BEGIN
declare @score int
select @score=english from Score where id=@id
IF(@score>60)
set @result='及格'
ELSE
set @result='不及格'

END
GO
--测试一
declare @id int
declare @temp varchar(50)
set @id=3
exec proc_getScore @id,@temp output
select @temp
  
最后一个例子,用C#来调用具有返回值的存储过程,这里我通过调用返回变量类型的存储过程来做测试。测试在控件台下进行,以下写了两种方法,第二种更好,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//方法一
//using (SqlConnection conn = new SqlConnection("server=.;database=myschool;uid=sa;pwd=123456"))
//{
// conn.Open();
// using (SqlCommand cmd = new SqlCommand("proc_getScore", conn))
// {
// cmd.CommandType = CommandType.StoredProcedure;
// cmd.Parameters.AddWithValue("@id", 2);
// SqlParameter sp = cmd.Parameters.Add("@result", SqlDbType.VarChar, 50); www.2cto.com
// sp.Direction = ParameterDirection.Output;
// cmd.ExecuteNonQuery();

        //       Console.Write(sp.Value); 
        //    } 
        //} 

        //方法二 
        using (SqlConnection conn = new SqlConnection("server=.;database=myschool;uid=sa;pwd=123456")) 
        { 
            conn.Open(); 
            using (SqlCommand cmd = new SqlCommand("proc_getScore", conn)) 
            { 
                cmd.CommandType = CommandType.StoredProcedure; 
                SqlParameter[] paras = {  
                    new SqlParameter("@id",SqlDbType.Int), 
                    new SqlParameter("@result",SqlDbType.NVarChar,50) 
                }; 

                paras[0].Value = 2; 
                paras[1].Direction = ParameterDirection.Output; 

                cmd.Parameters.AddRange(paras); 
                cmd.ExecuteNonQuery(); 

                Console.Write(paras[1].Value); 
            }  www.2cto.com   
        } 

        Console.ReadLine(); 

    } 
} 

}