什么是存储过程
如果你接触过其他的编程语言,那么就好理解了,存储过程就像是方法一样。竟然他是方法那么他就有类似的方法名,方法要传递的变量和返回结果,所以存储过程有存储过程名有存储过程参数也有返回值。
存储过程的优点:
- 存储过程的能力大大增强了SQL语言的功能和灵活性。
- 可保证数据的安全性和完整性。
- 通过存储过程可以使没有权限的用户在控制之下间接地存取数据库,从而保证数据的安全。
- 通过存储过程可以使相关的动作在一起发生,从而可以维护数据库的完整性。
- 在运行存储过程前,数据库已对其进行了语法和句法分析,并给出了优化执行方案。这种已经编译好的过程可极大地改善SQL语句的性能。
- 可以降低网络的通信量。
- 使体现企业规则的运算程序放入数据库服务器中,以便 集中控制。
存储过程可以分为系统存储过程、扩展存储过程和用户自定义的存储过程
系统存储过程
我们先来看一下系统存储过程,系统存储过程由系统定义,主要存放在MASTER数据库中,名称以"SP"开头或以"XP"开头。尽管这些系统存储过程在MASTER数据库中,但我们在其他数据库还是可以调用系统存储过程。有一些系统存储过程会在创建新的数据库的时候被自动创建在当前数据库中。
常用系统存储过程有:
- 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 --分离数据库
来看一下具体的代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
exec sp_databases--查看有哪些数据库use MySchoolexec 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 masterexec sp_renamedb 'myschool','school'--更改数据库名,为了更改成功,不能使用当前数据库,需切换到其他数据库exec sp_rename N'student.idx_cid', N'idx_cidd', N'index';--重命名索引exec sp_helpdb--数据库帮助,查询数据库信息--分离数据库use myschoolexec 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' |
用户自定义存储过程
在创建一个存储过程前,先来说一下存储过程的命名,看到好几篇讲存储过程的文章都喜欢在创建存储过程的时候加一个前缀,养成在存储过程名前加前缀的习惯很重要,虽然这只是一件很小的事情,但是往往小细节决定大成败。看到有的人喜欢这样加前缀,例如proc_名字。也看到这加样前缀usp_名字。前一种proc是procedure的简写,后一种sup意思是user procedure。我比较喜欢第一种,那么下面所有的存储过程名都以第一种来写。至于名字的写法采用骆驼命名法。
创建存储过程的语法如下:
CREATE PROC[EDURE] 存储过程名
@参数1 [数据类型]=[默认值] [OUTPUT]
@参数2 [数据类型]=[默认值] [OUTPUT]
AS
SQL语句
EXEC 过程名[参数]
来看一下各种不同的存储过程的实例:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
--创建不带参数的存储过程create procedure pro_studentas select * from student;--执行不带参数的存储过程exec pro_student;--修改不带参数的存储过程alter procedure pro_studentas select * from student where sid>3;--执行修改后的存储过程exec pro_student;--删除存储过程drop procedure pro_student;--创建带输出参数的存储过程create proc proc_getStudentRecord( @sex varchar(2) out, --输出参数 @age int output--输入输出参数)as select * from student where ssex = @sex and sage = @age;--不缓存在存储过程use myschool;create procedure proc_recompileStudentwith recompileas select * from student exec proc_recompileStudent--加密的存储过程create procedure proc_encrptStudentwith encryptionas select * from student; exec proc_recompileStudent |
存储过程返回值的方式
1、返回数字类型的存储过程(还没有想到返回字符串的方法)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
IF exists(select * from sys.objects where name='proc_getScore0') drop procedure proc_getScore0GO create procedure proc_getScore0( @id int)ASBEGIN declare @score int select @score=english from Score where id=@id IF(@score>60) return 0 ELSE return 1END--测试调用返回数字的存储过程<br>declare @t intEXEC @t = proc_getScore0 2select @t;--这里我遇到一个小问题,如果返回值是字符串,接收的时候declare @t nvarchar也出错,那该怎么做?--暂时没有想到 |
2、返回变量的存储过程
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
IF exists(select * from sys.objects where name='proc_getScore') drop procedure proc_getScoreGOCREATE PROCEDURE proc_getScore @id int, @result varchar(50) outputASBEGIN declare @score int select @score=english from Score where id=@id IF(@score>60) set @result='及格' ELSE set @result='不及格'ENDGO--测试一declare @id intdeclare @temp varchar(50)set @id=3exec proc_getScore @id,@temp outputselect @temp |
最后一个例子,用C#来调用具有返回值的存储过程,这里我通过调用返回变量类型的存储过程来做测试。测试在控件台下进行,以下写了两种方法,第二种更好,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
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); // 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); } } Console.ReadLine(); } }} |