服务器之家

服务器之家 > 正文

SQL数据库存储过程示例解析

时间:2020-05-04 16:22     来源/作者:张龙豪

什么是存储过程:存储过程可以说是一个记录集吧,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。

存储过程的好处:

1.由于数据库执行动作时,是先编译后执行的。然而存储过程是一个编译过的代码块,所以执行效率要比T-SQL语句高。

2.一个存储过程在程序在网络中交互时可以替代大堆的T-SQL语句,所以也能降低网络的通信量,提高通信速率。

3.通过存储过程能够使没有权限的用户在控制之下间接地存取数据库,从而确保数据的安全。

小结:总之存储过程是好东西,在做项目时属于必备利器,下面介绍存储过程的基本语法。

存储过程的语法和参数讲解

存储过程的一些基本语法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
--------------创建存储过程-----------------
 
CREATE PROC [ EDURE ] procedure_name [ ; number ]
  [ { @parameter data_type }
    [ VARYING ] [ = default ] [ OUTPUT ]
  ] [ ,...n ]
 
[ WITH
  { RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ]
 
[ FOR REPLICATION ]
 
AS sql_statement [ ...n ]
 
--------------调用存储过程-----------------
 
EXECUTE Procedure_name '' --存储过程如果有参数,后面加参数格式为:@参数名=value,也可直接为参数值value
 
--------------删除存储过程-----------------
 
drop procedure procedure_name  --在存储过程中能调用另外一个存储过程,而不能删除另外一个存储过程

创建存储过程的参数:
1.procedure_name :存储过程的名称,在前面加#为局部临时存储过程,加##为全局临时存储过程。

2.; number:是可选的整数,用来对同名的过程分组,以便用一条 DROP PROCEDURE 语句即可将同组的过程一起除去。例如,名为 orders 的应用程序使用的过程可以命名为 orderproc;1、orderproc;2 等。DROP PROCEDURE orderproc 语句将除去整个组。如果名称中包含定界标识符,则数字不应包含在标识符中,只应在 procedure_name 前后使用适当的定界符。

3.@parameter: 存储过程的参数。可以有一个或多个。用户必须在执行过程时提供每个所声明参数的值(除非定义了该参数的默认值)。存储过程最多可以有 2.100 个参数。
使用 @ 符号作为第一个字符来指定参数名称。参数名称必须符合标识符的规则。每个过程的参数仅用于该过程本身;相同的参数名称可以用在其它过程中。默认情况下,参数只能代替常量,而不能用于代替表名、列名或其它数据库对象的名称。有关更多信息,请参见 EXECUTE。

4.data_type:参数的数据类型。所有数据类型(包括 text、ntext 和 image)均可以用作存储过程的参数。不过,cursor 数据类型只能用于 OUTPUT 参数。如果指定的数据类型为 cursor,也必须同时指定 VARYING 和 OUTPUT 关键字。有关 SQL Server 提供的数据类型及其语法的更多信息,请参见数据类型。
说明 对于可以是 cursor 数据类型的输出参数,没有最大数目的限制。

5.VARYING: 指定作为输出参数支持的结果集(由存储过程动态构造,内容可以变化)。仅适用于游标参数。

6.default: 参数的默认值。如果定义了默认值,不必指定该参数的值即可执行过程。默认值必须是常量或 NULL。如果过程将对该参数使用 LIKE 关键字,那么默认值中可以包含通配符(%、_、[] 和 [^])。

7.OUTPUT :表明参数是返回参数。该选项的值可以返回给 EXEC[UTE]。使用 OUTPUT 参数可将信息返回给调用过程。Text、ntext 和 image 参数可用作 OUTPUT 参数。使用 OUTPUT 关键字的输出参数可以是游标占位符。

8.RECOMPILE: 表明 SQL Server 不会缓存该过程的计划,该过程将在运行时重新编译。在使用非典型值或临时值而不希望覆盖缓存在内存中的执行计划时,请使用 RECOMPILE 选项。

9.ENCRYPTION: 表示 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE 语句文本的条目。使用 ENCRYPTION 可防止将过程作为 SQL Server 复制的一部分发布。 说明 在升级过程中,SQL Server 利用存储在 syscomments 中的加密注释来重新创建加密过程。

10.FOR REPLICATION :指定不能在订阅服务器上执行为复制创建的存储过程。.使用 FOR REPLICATION 选项创建的存储过程可用作存储过程筛选,且只能在复制过程中执行。本选项不能和 WITH RECOMPILE 选项一起使用。

11.AS :指定过程要执行的操作。

12.sql_statement :过程中要包含的任意数目和类型的 Transact-SQL 语句。但有一些限制。

小结:看过这些基本语法后,下面我就根据语法创建各式的存储过程。

 创建存储过程

SQL数据库存储过程示例解析

针对上面的表,我使用存储过程对它做一些操作:

1. 只返回单一记录集的存储过程

?
1
2
3
4
5
6
7
8
-------------创建名为GetUserAccount的存储过程----------------
create Procedure GetUserAccount
as
select * from UserAccount
go
 
-------------执行上面的存储过程----------------
exec GetUserAccount

结果:相当于运行 select * from UserAccount 这行代码,结果为整个表的数据。

2.没有输入输出的存储过程

?
1
2
3
4
5
6
7
8
9
10
-------------创建名为GetUserAccount的存储过程----------------
 
create Procedure inUserAccount
as
insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(9,9,'2013-01-02',9)
go
 
-------------执行上面的存储过程----------------
 
exec inUserAccount

结果:相当于运行 insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(9,9,'2013-01-02',9) 这行代码。

3.有返回值的存储过程

?
1
2
3
4
5
6
7
8
9
10
11
-------------创建名为GetUserAccount的存储过程----------------
 
create Procedure inUserAccountRe
as
insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(10,10,'2013-01-02',10)
return @@rowcount
go
 
-------------执行上面的存储过程----------------
 
exec inUserAccountRe

解释:这里的@@rowcount为执行存储过程影响的行数,执行的结果是不仅插入了一条数据,还返回了一个值即 return value =1  ,这个可以在程序中获取,稍后在c#调用存储过程中会有说到。

4.有输入参数和输出参数的存储过程

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-------------创建名为GetUserAccount的存储过程----------------
 
create Procedure GetUserAccountRe
@UserName nchar(20),
@UserID int output
as
if(@UserName>5)
select @UserID=COUNT(*) from UserAccount where UserID>25
else
set @UserID=1000
go
 
-------------执行上面的存储过程----------------
 
exec GetUserAccountRe '7',null

解释:@UserName为输入参数,@UserID为输出参数。 运行结果为@userID为COOUT(*)即 =1。

5. 同时具有返回值、输入参数、输出参数的存储过程

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-------------创建名为GetUserAccount的存储过程----------------
 
create Procedure GetUserAccountRe1
@UserName nchar(20),
@UserID int output
as
if(@UserName>5)
select @UserID=COUNT(*) from UserAccount where UserID>25
else
set @UserID=1000
return @@rowcount
go
 
-------------执行上面的存储过程----------------
 
exec GetUserAccountRe1 '7',null

结果:@userID为COOUT(*)即 =1,Retun Value=1。

6.同时返回参数和记录集的存储过程

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-------------创建名为GetUserAccount的存储过程----------------
 
create Procedure GetUserAccountRe2
@UserName nchar(20),
@UserID int output
as
if(@UserName>5)
select @UserID=COUNT(*) from UserAccount where UserID>25
else
set @UserID=1000
select * from UserAccount
return @@rowcount
go
 
-------------执行上面的存储过程----------------
 
exec GetUserAccountRe2 '7',null

结果:返回执行 select * from UserAccount 这句代码的结果集,同时@userID为COOUT(*)即 =1,Retun Value=9。

7.返回多个记录集的存储过程

?
1
2
3
4
5
6
7
8
9
10
11
-------------创建名为GetUserAccount的存储过程----------------
 
create Procedure GetUserAccountRe3
as
select * from UserAccount
select * from UserAccount where UserID>5
go
 
-------------执行上面的存储过程----------------
 
exec GetUserAccountRe3

结果:返回两个结果集,一个为 select * from UserAccount,另一个为 select * from UserAccount where UserID>5 。

小结:上面我们创建了各式的存储过程,下面看我们在c#中怎样调用这些存储过程。

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
public partial class ProcedureTest : System.Web.UI.Page
  {
    public static string conn = ConfigurationManager.ConnectionStrings["StuRelationDBConnectionString"].ConnectionString;
    public SqlConnection con = new SqlConnection(conn);
    protected void Page_Load(object sender, EventArgs e)
    {
      runGetUserAccountRe3();
    }
 
    //只返回单一记录集的存储过程GetUserAccount
    public void runGetUserAccount()
    {
      SqlDataAdapter dp = new SqlDataAdapter(common("GetUserAccount"));
      DataSet ds = new DataSet();
      // 填充dataset
      dp.Fill(ds);
      rpt.DataSource = ds;
      rpt.DataBind();
 
    }
 
    //没有输入输出的存储过程inUserAccount
    public void runinUserAccount()
    {     
      con.Open();
      Label1.Text = common("inUserAccount").ExecuteNonQuery().ToString();
      con.Close();
    }
 
    //有返回值的存储过程inUserAccountRe
    public void runinUserAccountRe()
    {
      // 创建参数
      SqlCommand cmd = common("inUserAccountRe");
      IDataParameter[] parameters = {
         new SqlParameter("rval", SqlDbType.Int,4)
       };
      // 将参数类型设置为 返回值类型
      parameters[0].Direction = ParameterDirection.ReturnValue;
      // 添加参数
      cmd.Parameters.Add(parameters[0]);
      con.Open();
      // 执行存储过程并返回影响的行数
      Label1.Text = cmd.ExecuteNonQuery().ToString();
      con.Close();
      // 显示影响的行数和返回值
      Label1.Text += "-" + parameters[0].Value.ToString();
    }
 
    //有输入参数和输出参数的存储过程
    public void runGetUserAccountRe()
    {
      SqlCommand cmd = common("GetUserAccountRe");
      // 创建参数
      IDataParameter[] parameters = {
         new SqlParameter("@UserName", SqlDbType.NChar,20) ,
         new SqlParameter("@UserID", SqlDbType.Int) ,
       };
      // 设置参数类型
      parameters[0].Value = "7";
      parameters[1].Direction = ParameterDirection.Output; // 设置为输出参数
      // 添加参数
      cmd.Parameters.Add(parameters[0]);
      cmd.Parameters.Add(parameters[1]);
      con.Open();
      // 执行存储过程并返回影响的行数
      Label1.Text = cmd.ExecuteNonQuery().ToString();
      con.Close();     
      // 显示影响的行数和输出参数
      Label1.Text += "-" + parameters[1].Value.ToString();
      
    }
 
    //同时具有返回值、输入参数、输出参数的存储过程GetUserAccountRe1
    public void runGetUserAccountRe1()
    {
      SqlCommand cmd = common("GetUserAccountRe1");
      // 创建参数
      IDataParameter[] parameters = {
         new SqlParameter("@UserName", SqlDbType.NChar,20) ,
         new SqlParameter("@UserID", SqlDbType.Int) ,
         new SqlParameter("rval", SqlDbType.Int,4)
       };
      // 设置参数类型
      parameters[0].Value = "7";
      parameters[1].Direction = ParameterDirection.Output; // 设置为输出参数
      parameters[2].Direction = ParameterDirection.ReturnValue; //设置为返回值
      // 添加参数
      cmd.Parameters.Add(parameters[0]);
      cmd.Parameters.Add(parameters[1]);
      cmd.Parameters.Add(parameters[2]);
      con.Open();
      // 执行存储过程并返回影响的行数
      Label1.Text = cmd.ExecuteNonQuery().ToString();
      con.Close();
      // 显示影响的行数和输出参数
      Label1.Text += "-输出参数为:" + parameters[1].Value.ToString();
      Label1.Text += "-返回值为:" + parameters[2].Value.ToString();
 
    }
 
    //同时返回参数和记录集的存储过程GetUserAccountRe2
    public void runGetUserAccountRe2()
    {
      SqlCommand cmd = common("GetUserAccountRe2");
      // 创建参数
      IDataParameter[] parameters = {
         new SqlParameter("@UserName", SqlDbType.NChar,20) ,
         new SqlParameter("@UserID", SqlDbType.Int) ,
         new SqlParameter("rval", SqlDbType.Int,4)
       };
      // 设置参数类型
      parameters[0].Value = "7";
      parameters[1].Direction = ParameterDirection.Output; // 设置为输出参数
      parameters[2].Direction = ParameterDirection.ReturnValue; //设置为返回值
      // 添加参数
      cmd.Parameters.Add(parameters[0]);
      cmd.Parameters.Add(parameters[1]);
      cmd.Parameters.Add(parameters[2]);
      con.Open();
      // 执行存储过程并返回影响的行数
      Label1.Text = cmd.ExecuteNonQuery().ToString();
      DataSet ds = new DataSet();
      SqlDataAdapter dt = new SqlDataAdapter(cmd);
      dt.Fill(ds);
      rpt.DataSource = ds;
      rpt.DataBind();
      con.Close();
      // 显示影响的行数和输出参数
      Label1.Text += "-输出参数为:" + parameters[1].Value.ToString();
      Label1.Text += "-返回值为:" + parameters[2].Value.ToString();
 
    }
 
    //返回多个记录集的存储过程
    public void runGetUserAccountRe3()
    {
      DataSet ds = new DataSet();
      SqlDataAdapter dt = new SqlDataAdapter(common("GetUserAccountRe3"));
      dt.Fill(ds);
      rpt1.DataSource = ds.Tables[0].DefaultView;
      rpt1.DataBind();
      rpt2.DataSource = ds.Tables[1].DefaultView;
      rpt2.DataBind();
    }
    
    public SqlCommand common(string proName)
    {
      
      SqlCommand cmd = new SqlCommand();
      // 设置sql连接
      cmd.Connection = con;     
      // 如果执行语句
      cmd.CommandText = proName;
      // 指定执行语句为存储过程
      cmd.CommandType = CommandType.StoredProcedure;
      return cmd;
    }
  }

附带SQLServer数据库的一些全局变量

?
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
select APP_NAME ( ) as w --当前会话的应用程序
 
select @@IDENTITY  --返回最后插入的标识值
select USER_NAME()  --返回用户数据库用户名
 
SELECT @@CONNECTIONS --返回自上次SQL启动以来连接或试图连接的次数。
SELECT GETDATE() --当前时间
SELECT @@CPU_BUSY/100 --返回自上次启动SQL 以来 CPU 的工作时间,单位为毫秒
 
USE tempdb SELECT @@DBTS as w --为当前数据库返回当前 timestamp 数据类型的值。这一 timestamp 值保证在数据库中是唯一的。
select @@IDENTITY as w --返回最后插入的标识值
SELECT @@IDLE as w --返回SQL自上次启动后闲置的时间,单位为毫秒
SELECT @@IO_BUSY AS --返回SQL自上次启动后用于执行输入和输出操作的时间,单位为毫秒
SELECT @@LANGID AS --返回当前所使用语言的本地语言标识符(ID)。
SELECT @@LANGUAGE AS --返回当前使用的语言名
SELECT @@LOCK_TIMEOUT as w --当前会话的当前锁超时设置,单位为毫秒。
SELECT @@MAX_CONNECTIONS as w --返回SQL上允许的同时用户连接的最大数。返回的数不必为当前配置的数值
EXEC sp_configure --显示当前服务器的全局配置设置
SELECT @@MAX_PRECISION as w --返回 decimal 和 numeric 数据类型所用的精度级别,即该服务器中当前设置的精度。默认最大精度38。
select @@OPTIONS as w --返回当前 SET 选项的信息。
SELECT @@PACK_RECEIVED as w --返回SQL自启动后从网络上读取的输入数据包数目。
SELECT @@PACK_SENT as w --返回SQ自上次启动后写到网络上的输出数据包数目。
SELECT @@PACKET_ERRORS as w --返回自SQL启动后,在SQL连接上发生的网络数据包错误数。
SELECT @@SERVERNAME as w --返回运行SQL服务器名称。
SELECT @@SERVICENAME as w --返回SQL正在其下运行的注册表键名
SELECT @@TIMETICKS as w --返回SQL服务器一刻度的微秒数
SELECT @@TOTAL_ERRORS AS w --返回 SQL服务器自启动后,所遇到的磁盘读/写错误数。
SELECT @@TOTAL_READ as w --返回 SQL服务器自启动后读取磁盘的次数。
SELECT @@TOTAL_WRITE as w --返回SQL服务器自启动后写入磁盘的次数。
SELECT @@TRANCOUNT as w --返回当前连接的活动事务数。
SELECT @@VERSION as w --返回SQL服务器安装的日期、版本和处理器类型。

以上就是本文的全部内容,希望对大家的学习有所帮助。

相关文章

热门资讯

沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意
沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意 2019-07-07
玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分
玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分 2019-06-21
男生常说24816是什么意思?女生说13579是什么意思?
男生常说24816是什么意思?女生说13579是什么意思? 2019-09-17
超A是什么意思 你好a表达的是什么
超A是什么意思 你好a表达的是什么 2019-06-06
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享 2020-04-07
返回顶部