SQL Server与MySQL存储过程学习记录之一

SQL语句执行的时候要先编译,然后执行。

存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。

  SQL Server的存储过程在设计BNU校园百科的时候就有使用,因为存储过程不仅能提高SQL语言的执行效率,同时参数化的调用比每次都写一条SQL语句来得方便。


【SQL Server存储过程的建立】

  在企业管理器新建一个StoreProcedure会自动生成相应导航代码,方便用户编写函数。

SQL Server与MySQL存储过程学习记录之一_第1张图片

-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters 
-- command (Ctrl-Shift-M) to fill in the parameter 
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:   <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE <Procedure_Name, sysname, ProcedureName> 
-- Add the parameters for the stored procedure here
<@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>, 
<@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

    -- Insert statements for procedure here
SELECT <@Param1, sysname, @p1>, <@Param2, sysname, @p2>
END
GO

  我们现在设计一个带参数的存储过程,比如我们经常需要使用这样的一类查询:包含keyword的所有结果集,这个时候为该查询实现一个存储过程如下

CREATE PROCEDURE [dbo].[p_SearchByKeyWord]
@keyword nvarchar(200)
AS
BEGIN
SELECT * From [myTable] where [myWordColumn] like '%'+@keyword+'%'
END
GO


  在SQL Server中调用存储过程的方法是使用EXEC命令,比如我们要查包含“北京师范大学”的所有记录,我们运行如下T-SQL命令

EXEC p_SearchByKeyWord  @keyword = '北京师范大学'

  就能得到结果集如下:如果有多个参数,需要用逗号隔开分别传入,即

EXEC myProcedureName  @parameter1='×××',@parameter2='×××',......

SQL Server与MySQL存储过程学习记录之一_第2张图片

  如果想要修改已经存在的存储过程,只要把CREATE换成ALTER即可,比如我们限定查询数量为100条记录,修改已经建立的p_SearchByKeyWord

ALTER PROCEDURE  [dbo].[p_SearchByKeyWord]
@keyword nvarchar(200)
AS
BEGIN
SELECT TOP 100 * From [myTable] where [myWordColumn] like '%'+@keyword+'%'
END
GO

  删除存储过程就更简单了,直接使用DROP命令,比如

DROP PROCEDURE [dbo].[p_SearchByKeyWord]


【MySQL存储过程的建立】

  MySQL存储过车的创建、修改、删除语法与SQL Server类似,但是参数定义和调用方式都不一样,所以需要花时间看官方的手册!

  MYSQL没有提供微软企业管理那样的强大前端,当然就没有创建存储过程的向导,但是一旦熟悉了存储过程建立的方法,就觉得自己手写要方便得多。即使有很多第三方的MySQL前端,如Navicat提供了向导式的存储过程建立,但是为了了解底层的语法细节,手动编写每一步是很重要的。下面来看MySQL的存储过程建立方式。

  官方说明有这样一段

CREATE
    [DEFINER = { user | CURRENT_USER }]
    PROCEDURE sp_name ([proc_parameter[,...]])
    [characteristic ...] routine_body
    
proc_parameter:
    [ IN | OUT | INOUT ] param_name type

type:
    Any valid MySQL data type

characteristic:
    LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'

routine_body:
    Valid SQL procedure statement

  很好理解,比如我们要创建一个简单的不带参数的存储过程p_Test,只需如下极短的代码

CREATE p_Test()
BEGIN
Select * FROM [myTable] LIMIT 100;
END;

  其中BEGINEND块是存储过程的核心,这个与SQL Server相同。另外,需要注意的是,不管有没有参数,存储过程名称后面需要有一个括号,这个与SQL Server是不相同的(有参数和没有参数均不需要任何括号),所以不要忘了。

  现在来创建一个带有参数的查询,记住,所有参数都要包含在刚才所说的括号中。比如我们需要统计在给定两个时间点的所有访问记录数,于是每次调用需要传入起始时间和结束时间,于是需要指定两个参数,如下 _starttime 和 _endtime ,这两个变量之前的 IN 用来修饰参数,表示是输入变量,也可以忽略(默认即输入),也可以显示指定为OUT(输出变量),INOUT(既作为输入,也作为输出,在某些复杂的程序中可能会遇到)

CREATE PROCEDURE p_GetVisitCountByTime(
IN _starttime datetime,
IN _endtime datetime
)
BEGIN
SELECT COUNT(VISIT_ID) AS total FROM myTable
             WHERE VISIT_TIME>=_starttime and 
             VISIT_TIME<_endtime and;
END;

  创建好之后就能调用了,注意MySQL调用存储过程的方法和SQL Server是不一样的,需要使用语法CALL,然后参数全部包含在括号里面,比如

CALL p_GetVisitCountByTime('2009-12-01 00:00:00','2009-12-02 00:00:00');

  这句话查询在09年12月1号到12月2号的总访问人数,清晰明了。

  最后说明一些要注意的地方,也是SQL Server与MySQL差异的地方,在编写存储过程的时候,SQL Server并不需要在每个块结束后使用分号,但是MySQL需要在每个块结束后使用分号标识,比如

CREATE p_Test()
BEGIN
Select * FROM [myTable] LIMIT 100;
END--这里没有分号

  那么会提示编译错误,同样,如果是这样

CREATE p_Test()
BEGIN
Select * FROM [myTable] LIMIT 100--这里没有分号
END;

  那么也会提示编译错误,所以在MySQL里一定不要忘了分号,当然SQL Server则不需要分号!

  更多关于存储过程里循环、条件、定义内部变量等高级的应用和使用上的差异会在学习记录之二再谈,其实也就是SQL Server和MySQL的编程语法!

  总结一下,由于存储过程是数据库的一个重要部分,因此不同的数据库都有起实现方式,但是思想是一致的,在学习不同数据库相应操作的时候,应该进行类比学习,这样在做特定应用的时候就能更加顺手!我也是现在经常遇到基于MySQL的项目才开始关注MySQL的各种细节!

  可以继续阅读学习记录之二


在学习记录一中,讨论了SQL Server与MySQL各自建立存储过程的方法和过程,并简单做了一下对比。在实际应用中,查询往往是很复杂的,不可能用一简单的一行SQL语言就能满足我们的需求,这个时候,就需要使用SQL编程。

  实现SQL编程有两种方式,第一种就是用高级语言进行反复调用,因为我们熟悉一门或多门高级程序语言,比如C,C++,C#,PHP,Java等等,这些都是能调用数据库操作的。比如在C#这样的面向对象编程语言里,万物皆对象,在创建一个数据库调用程序时,首先需要新建一个连接,同时建立一条SQL操作指令,然后打开连接,执行该指令,最后返回结果,关闭连接。

  首先以C#调用SQL Server为例,比如我们要运行一条没有返回结果的SQL语句并赋值给sqlStr字符串变量,那么用简单的几行程序就能直接操作数据库了。(需要System.Data和System.Data.SqlClient命名空间)

SqlConnection sqlConn = new SqlConnection(connectStr);
SqlCommand sqlCmd = new SqlCommand(sqlStr, sqlConn);
sqlConn.Open();
sqlCmd.ExecuteNonQuery();
sqlConn.Close();

  于是,要进行复杂的SQL操作时,只要保持数据库的连接打开,不断改变SqlCommand命令来实现不同的操作,如动态生成sqlStr。

  同样的,使用C#连接MySQL数据库时,需要下载MySQL Connector NET,这是一个封装好的用来连接MySQL的类库,所有命令和连接SQL Server毫无差别,只需把Sql换成MySql即可,如下。(需要MySql.Data和MySql.Data.MySqlClient命名空间)

MySqlConnection sqlConn = new MySqlConnection(connectStr);
MySqlCommand sqlCmd = new MySqlCommand(sqlStr, sqlConn);
sqlConn.Open();
sqlCmd.ExecuteNonQuery();
sqlConn.Close();

  但是如果要批量执行SQL语言,通过高级语言循环方式传入不免带来效率上的劣势,因为每次传入的SQL语句都要先编译,然后运行,同时在传送SQL命令的时候也有时间代价(尤其是远程数据库),为何不只传送一条命令,然后在数据库里进行批量执行呢?这也就是存储过程的好处,可以把存储过程看成数据库操作的一个宏,或者批处理。当然,这要数据库支持才行。高兴的是,目前的所有企业级数据库都很好的支持了SQL编程,只是实现细节有差别。下面具体谈谈SQL Server与MySQL的SQL编程方法。


【SQL Server简单编程】

该部分转自http://www.cnblogs.com/Niyowong/archive/2007/08/20/862169.html,如果要学习更高级的内容可以购买人民邮电出版社的《SQL Server 2008基础教程》

1.局部变量

声明单个局部变量

declare @num int

声明多个局部变量

declare   @FirstName nvarchar(20)
                @LastName nvarchar(20)
                @Age int

局部变量赋值
被赋值的局部变量必须是已经声明的。

a.简单赋值方法

declare @UserName varchar(10)
set @UserName = 'Niyo Wong'

b.使用select语句赋值

delcare @NoOfRecords int
set @NoOfRecords = (select count(*) from tableName)
select @NoOfRecords = 20
declare @UserName varchar(20)
declare @UserId varchar(10)
select @UserName = userName from tbl_User where userId = '123401'
select @UserId = max(UserId) from tbl_User

注意:如果查询返回了多个值时,那么只有最后一个值赋给了变量。

c.使用update语句赋值

declare @qyt tinying
update tableName set @qty = fieldName where id = '1'
注意:update无法象select语句一样魏数据提供一些常用的转换,所以在使用update进行赋值时,
最好严格匹配数据类型,否则会产生错误。

2.全局变量

下面列举几个我们在编程中常用的全局变量

a. @@CURSOR_ROWS

返回本次服务器连接中,打开游标取回的数据行的数目。如:

select @@CURSOR_ROWS
declare employee_cursor cursor for
select emplid from tbl_Employee
open employee_cursor
fetch next from employee_cursor
select @@CURSOR_ROWS
close employee_cursor
deallocate employee_cursor

b. @@ERROR

返回上一条语句返回的错误号,执行成功返回0,
一般在insert,update,delete语句之后使用(常结合事务处理)。

c. @@FETCH_STATUS

返回上一次使用游标FETCH操作所返回的状态值。返回值为0表示操作成功,
为-1表示操作失败或者已经超过了游标所能操作的数据行的范围,当到了最后一行数据后,
还要接着取下一列数据,返回-2,表示返回值已经丢失。

d. @@ROWSCOUNT

返回上一条SQL语句所影响到的数据行的数据。常用于检查操作是否达到了目的,
当执行的SQL语句不影响数据库数据时,该变量返回0

e. @@VERSION

返回版本号

3.结构语句

a.条件结构
if.... else ...如:

if((select count(*) from table1) > 0)
begin
declare @num int
set @num = (select max(no) from tabl2)
if(@num >(select count(*) from table1))
begin
print '@num >(select count(*) from table1)'
end
else
if(@num = (select count(*) from table1))
begin
   print '@num = (select count(*) from table1)'
end
end
else
begin
print 'No of record below zero'
end

b.循环结构
while 语句。如:

declare @count int
set @count = 0
while(@count < 10)
begin
print @count
set @count = @count + 1 
end

在循环中常用的语句有break和continue,
break为跳出while,而continue为跳出当前循环,进入下一循环。
有时候也用到return和goto语句,下面我们将讲这两个语句。

c.case语句
case语句又叫条件分支语句。如:

select case userType 
when '1' then 'admin' 
when '2' then 'general user' 
else 'other' end 'userType' 
from tbl_user

或者

select 'userType' = case
when USERiD = '1' then 'admin'
when userName = 'Lucy' then 'admin'
when userType = '1' then 'admin'
when userType = '2' then 'general user'
else 'other' end
from tbl_user

注意:case语句中when匹配成功后,就到end,不会匹配下一个when,
所以如果有一条记录,userid = '1' 并且usertype = '2',
则返回uertype是‘admin'而不是’general user'

d.return语句
立即退出程序,return后面的语句将不执行。return 后常跟一个整形表达式作为返回值。

e.goto语句(最好不用goto语法)
跳转到跟在goto后面的标签位置。如

declare @count int
              @value int
set @count = (select count(*) from table)
if(@count = 0)
begin
    set @value = 0
    goto Flag
end
set @value = @count + 10
Flag:
print @value


【MySQL简单编程】

  MySQL编程与SQL Server类似,也要包含在所谓的区块BEGIN和END里,同时END后面必须要有分号(SQL Server不需要分号)。下面具体讲解变量定义、条件、循环的基本语法。

1、变量定义

declare varname vartype;

比如 declare a int--定义一个整型变量a,也可以用default来声明默认赋值,如 declare a int default 5

2、结构语句

a.定义区块

BEGIN
--sqlStr
END;

或自定义区块名称

LABEL:BEGIN
--sqlStr
END LABEL;
这样就可以用LEAVE LABEL;跳出区块,执行区块以后的代码

b.条件语句

if 条件 then
--my statement
else
--my statement
end if;

c.循环语句

[label:] WHILE expression DO
--sqlStr
END WHILE [label] ;

[label:] LOOP
--sqlStr
END LOOP [label];

[label:] REPEAT
--sqlStr
UNTIL expression
END REPEAT [label];

下面写一个综合的程序如下

create procedrue p_test()
begin
declare a int;
set a=0;
while a<10 do
set a = a+1;
end while;
select a;
end;

  可以看到,使用MySQL编程和SQL Server基本思想是一致的,语法有较大的区别。SQL Server不管是条件、循环等区块仍然要使用begin与end作为起始和结束的标识,而MySQL则直接用END something(如while,if,loop),当然,由于自己接触MySQL并不长,没有使用SQL Server那么熟练,所以写这些也是非常基础的部分,而在实际问题中会千变万化,所以还是需要更多的实践来不断提高。


你可能感兴趣的:(SQL Server与MySQL存储过程学习记录之一)