精华内容
下载资源
问答
  • 使用存储过程的优点 作为服务器端的代码,存储过程具有以下优点:1) 存储过程是预先编译过的,是执行查询或者批处理的最快方法.2)在服务器而不是桌面计算机上执行程序可以极大地降低网络流量.3)存储过程是模块化的,易于...

    原文发布时间为:2008-09-26 —— 来源于本人的百度文章 [由搬家工具导入]

    一.使用存储过程的优点

       作为服务器端的代码,存储过程具有以下优点:
    1) 存储过程是预先编译过的,是执行查询或者批处理的最快方法.
    2)在服务器而不是桌面计算机上执行程序可以极大地降低网络流量.
    3)存储过程是模块化的,易于部署,代码也容易修改.如果前端的程序是通过调用存储过程就可以升级所有

    客户的应用程序
    4)存储过程是数据库安全性的一个重要组成部分.如果所有的用户都是通过存储过程来访问数据,那么,就

    可以禁止用户对表的直接访问,并控制所有对数据的访问.


    二.在.NET中使用存储过程中一个简单示例:


       private SqlCommand GetLoadCommand()
            {
                if ( loadCommand == null )
                {
                    //
                    // Construct the command since we don't have it already
                    //
                    loadCommand = new SqlCommand("GetCustomerByEmail",new SqlConnection

    (DuwamishConfiguration.ConnectionString));
                    loadCommand.CommandType = CommandType.StoredProcedure;
           
                    loadCommand.Parameters.Add(new SqlParameter(EMAIL_PARM, SqlDbType.NVarChar,

    50));
                }
               
                return loadCommand;
            }

       在初始化SqlCommand的参数中"GetCustomerByEmail"就是存储过程的名称,而SqlCommand另外一个参数

    是sqlconnection参数,用于链接数据库.而在"GetCustomerByEmail"的参数可以直接写成sql的查询语句,

    在此处使用存储过程不但是读取和修改数据库的过程更易于管理,而且执行速度会加快
       在数据库"GetCustomerByEmail"的存储过程为:
       --------------------------------------------------
    -- GetCustomerByEmail
    --------------------------------------------------
    CREATE PROCEDURE GetCustomerByEmail
        @Email NVARCHAR(50) = NULL
    AS
        SET NOCOUNT ON

        SELECT c.PKId,
               c.Email,
               c.Password,
               c.Name,
               a.Address,
               a.Country,
               a.PhoneNumber,
               a.Fax
          FROM Customers c,
               Addresses a
         WHERE c.Email = @Email
           AND a.CustomerId = c.PKId

        RETURN 0
    --------------------------------------------------
    -- unique index on Customers (Email)
    -- duplicate index on Addresses (CustomerId)
    --------------------------------------------------

    GO

    三. 存储过程基本语法:(要详细了解存储过程里的语法,推荐看"使用Transact-SQL编程")


    1.向存储过程传递数据
       1)可以在create procedure命令中的存储过程名之后列出要添加的参数.每个 参数都必须以@打头.它

    会成为该存储过程中的局部变量
       2)在调用存储过程中,必须为这些输入变量提供值
    例子:
    create procedure CategoryGet( @CategoryName NVARCHAR(35))
    AS
    select ProductCategoryNameProductCategoryDesription
    From dbo.ProductCategory
    Where ProductCategorName=@CategoryName


    EXEC CategoryGet 'Kite'

    2. 参数的默认值
    CREATE PROCEDURE StroredProcedure(
    @Variable DateType =DefaultVaule
    )

    3.从存储过程返回数据
    1) 输出参数:无论在创建存储过程的时候,还是在调用它的时候,都必须使用关键字output.在存储过程中,

    输出参数就像是局部变量一样.在调用存储过程的程序或者批处理中,必须在调用存储过程之前创建接收输

    出参数数据的变量.当存储过程执行完毕后,就会将输出参数的当前值传递给调用过程的局部变量.

    例子:
    Create proc GetProductName(
       @ProductCode CHAR(10),
       @ProductName VARCHAR(25) OUTPUT)
    AS
    Select @ProductName = ProductName
    From dbo.Product
    WHERE Code = @ProductCode

    调用该存储过程的批处理如下:
    Declare @ProdName VARCHAR(25)
    EXEC GetProductName '1001', @ProdName OURPUT
    Print @ProdName


    4. 使用RETURN命令
       return命令会无条件地终止存储过程地执行,并向调用它地批处理或者客户返回一个值.
       返回值0表示执行成功,它也是默认的返回值.-99到-1之间的值是Microsoft保留给SQLServer使用的,所

    以建议使用-100或者更小的值来返回失败的状态.
       在调用存储过程时,必须按照如下方式在exec命令中使用一个局部的整数型变量来获取返回的状态值.
    DECLARE @IntLocalVariable INT
    EXEC @IntLocalVariable= StoredProcedureName

    5. 返回数据的途径及其适用范围
       任意存储过程在选择返回数据的方法时都面临着4种可能(select, raiserror,输出参数和return)
       适用范围如下:
       1)return和输出参数(output parameters)都是将数据返回给SQLserver中直接调用存储过程的程序或

    者批处理
       2)raiserror和select语句返回的记录集都是直接返回给最终用户的客户应用程序的


    四. 调试存储过程:


    1)查看结果:
        打开查询分析器,找到需要调试的存储过程,并按右键--打开,即会出现一个"执行过程"的窗口,只要把

    所有参数值都赋好值,就可以看到该存储过程的执行结果
    2)单步跟踪:
        同样打开查询分析器,找到需要调试的存储过程,并按右键--调试.调试器所要完成的全部工作就是一

    次一条命令地执行存储过程.使用工具条上的按钮可以对单步执行代码的过程进行控制.在单步执行过程的

    时候,使用"单步进入"(Step into)可以 执行单条命令.使用"单步跳过"(Step over)按钮也可以执行单条

    命令,如果当前的命令调用了另一个存储过程,它将会把这个存储过程作为一个完整的单元来执行,不会跟

    踪进入.使用"运行至光标"(Step to cursor)按钮可以连续执行多条命令,知道光标所指定的那一行命令为

    止.

    注:要赋予登陆用户系统管理员的权限,才可以进行对存储过程的调试.

    转载于:https://www.cnblogs.com/handboy/p/7148402.html

    展开全文
  • 1.1 使用存储过程的优点 存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。 当对数据库进行复杂操作时(如对多个表...

    存储过程

    一、存储过程和概述

    针对表的一个完整操作有时候并不是单条SQL语句就能实现的,而是需要一组SQL语句来实现。例如,当老师不慎填写错误,要对一个同学的期末成绩进行修改,一般需要考虑以下几步:
    在这里插入图片描述
    可将一个完整操作中所包含的多条SQL语句创建为存储过程,以方便应用。

    1.1 使用存储过程的优点

    1. 存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度
    2. 当对数据库进行复杂操作时(如对多个表进行Update、Insert、Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。
    3. 存储过程可以重复使用,可减少数据库开发人员的工作量
    4. 安全性高,可设定只有某此用户才具有对指定存储过程的使用权。

    二、创建并调用存储过程

    存储程序可以分为存储过程和。存储过程的操作主要包括创建存储过程、调用存储过程、查看存储过程,以及修改和删除存储过程。

    1. 创建存储过程使用SQL语句CREATE PROCEDURE来实现,其语法形式如下:
    CREATE PROCEDURE proc_name ( proc_parameter[,] )
    begin
    routine_body
    end
    

    proc_parameter表示存储过程的参数,参数形式如下:

    
    [ IN | OUT | INOUT ] parameter_name TYPE
    
    1. 删除存储过程使用SQL语句DROP PROCEDURE来实现,其语法形式如下:
    DROP PROCEDURE proc_name
    

    使用SHOW CREATE语句可以查看存储过程的定义语句,语法形式如下:

    SHOW CREATE PROCEDURE  pf_name;
    
    1. 存储过程必须使用关键字CALL调用。通常使用关键字CALL调用存储过程,其语法形式如下:
    CALL procedure_name([parameter[,]]);
    

    2.1 实践

    题目一:创建一个名为p_snum的简单存储过程,用于获取所有的学生总数
    在创建存储过程前首先登录MySQL,并选择数据库xkgl。然后执行以下语句

    
    mysql-> CREATE PROCEDURE p_snum()
             -> SELECT COUNT(*) FROM student;
    Query OK, 0 rows affected (0.03 sec)
    
    

    **题目二```:创建一个名为p_cnum()的存储过程,用来获取没有班长的班级信息,建立这个存储过程并调用

    create procedure p_cnum()
    begin
    select * from class where Monitor is NULL;
    end;
    
    # 调用
    call p_cnum();
    # 删除
    drop procedure p_cnum;
    

    调用存储过程的执行结果与直接执行查询语句SELECT COUNT(*) FROM student;的执行结果相同,但是存储过程的好处在于处理逻辑都封装在数据库端,调用者不需要了解中间的处理逻辑,当处理逻辑发生变化时,只需要修改存储过程即可,而对调用者的程序完全没有影响。

    题目三:创建一个名为p_snum_fsex的存储过程,用于获取所有的学生总数和学生的所有信息。

    mysql> DELIMITER $$
    mysql> CREATE PROCEDURE p_snum_fsex()
        -> BEGIN
        -> SELECT COUNT(*) FROM student;
        -> SELECT * FROM student;
        -> END $$
    Query OK, 0 rows affected (0.03 sec)
    mysql> DELIMITER;
    
    

    TipsDELIMITER $$的作用是将语句的结束符;修改为$$,这样存储过程中的SQL语句结束符;就不会被MySQL解释成语句的结束而提示错误。在存储过程创建完成后,应使用DELIMITER ;语句将结束符修改为默认结束符。

    三、关于存储过程和的表达式

    3.1 变量的分类

    • 用户变量(User-Defined Variables):带有前缀@,只能被定义它的用户使用,作用于当前整个连接,当前连接断开后,所定义的用户变量会被全部释放。用户变量不用提前定义就可以直接使用。
    • 局部变量(Local Variables):没有前缀,一般用于SQL语句块中,比如存储过程的BEGIN…END中。局部变量使用前需要先通过DECLARE声明。如没有声明,则初始值为NULL

    3.2 在存储过程中应用变量

    局部变量可以在子程序中定义并应用,其作用范围是BEGIN…END语句块。

    • 定义变量
      在存储过程中使用DECLARE语句定义局部变量,其语法形式如下:
    DECLARE var_name[,] type [DEFAULT value];
    例如,定义一个INT类型的变量,名称为var1:
    DECLARE var1 INT;
    

    Tips:变量的定义必须在复合语句开头,并且在任何其他语句前面。也就是说,DECLARE语句在存储过程和中使用时,必须出现在BEGIN…END语句块的最前面,并且变量名不区分大小写。可以一次声明多个相同类型的变量。

    • 为变量赋值
      定义变量之后,可以使用SET关键字为变量赋值,语法形式如下:
    SET var_name = expr [,var_name = expr];
    

    为前面定义的变量var1赋值或者全部变量,具体如下

    SET var1 = 3;set @var1=3

    变量值可以为常量或者表达式。

    另外,也可以使用SELECT…INTO…查询语句将查询结果赋给变量,这要求查询结果必须只有一行,具体语法形式如下:

    SELECT col_name[,……] INTO var_name[,……] FROM table_name;
    

    当存储过程涉及到输入输出值时,则需要用到参数:
    参数:设置 MySQL存储过程的参数,用在存储过程的定义,共有三种参数类型:IN,OUT,INOUT

    基本语句
    CREATE PROCEDURE([[IN |OUT |INOUT ] 参数名 数据类形...])
    IN 输入参数:表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被改变返回,为默认值
    OUT 输出参数:该值可在存储过程内部被改变,并可返回
    INOUT 输入输出参数:调用时指定,并且可被改变和返回

    3.3 实践

    题目一:创建一个存储过程,将输入的值加2后输出

    create procedure p_in(in a int)
    begin
    select a;
    set a = a + 2;
    select a;
    end;
    # 调用
    call p_in(5);
    

    题目二:创建一个存储过程,通过out参数向外输出2

    create procedure demo_out_parameter(out p_out int)
    begin
    	select p_out;
    	set p_out = 2;
    	select p_out;
    end;
    
    call demo_out_parameter(@a);
    select @a;
    

    题目三:[利用inout]创建一个存储过程,将输入的值加2后输出

    create procedure p_inout(inout p_io int)
    begin
    	select p_io;
    	set p_io = p_io + 2;
    	select p_io;
    end;
    
    -- 输入数值为3,得到传出的输出值,然后查看
    set @a = 3;
    select @a;
    call p_inout(@a);
    select @a;
    
    

    题目四:创建一个存储过程,输入某个班级,输出某个班级的人数

    create procedure p_classnum(in claid char(10) ,out cnum int)
    begin
    select count(*) from student where classid = claid;
    end;
    
    select * from class;
    # 查找Cs010901班级的人数
    call p_classnum('Cs010901',@num);
    

    题目五:创建一个名为p_garde的存储过程,通过输入的学生号和课程号,得到该同学该门课的成绩,然后将成绩传递给p_pass函数,该函数可以通过输入的成绩,输出该成绩是否及格。

    create procedure p_grade(in sid char(12),in cid char(8),out cj decimal(5,1))
    	begin
    	select grade into cj from grade where studentid = sid and courseid = cid;
    end;
    
    create procedure p_pass(in cj decimal(5,1),out result char(10))
    begin 
    	if cj >= 60 then set result = '及格';
    	else set result = '不及格';
    	end if;
    end;
    
    select * from grade;
    call p_grade('St0109010001','Dp010001',@grade);
    call p_pass(@grade,@result);
    select @result;
    
    drop procedure p_grade;
    
    

    扩展:将上面的合并到一个存储过程中

    
    create procedure p_gp()
    begin
    	call p_grade('St0109010001','Dp010001',@grade);
    	call p_pass(@grade,@result);
    	select @result;
    end;
    
    call p_gp();
    

    题目六:建立一个存储过程p_add_grade,这个存储过程作用是可以给某个同学某门课程加两分(表内数据直接加2分)

    create procedure p_add_grade(in sid char(15),in cid char(10),out g int)
    begin
    	select grade into g from grade where StudentID = sid and CourseID = cid;
    	set g = g + 2;
    end;
    
    drop procedure p_add_grade;
    
    select * from grade;
    call p_add_grade('St0109010001','Dp010001',@grade);
    select @grade;
    

    题目七:创建存储过程,判断两个输入的参数哪一个更大,并输出较大的参数值。

    create procedure p_max(in a int,in b int ,out max int)
    begin
    	if a>b then set max = a;
    	elseif a<b then set max = b;
    	else set max = a;
    	end if;
    	select max;
    end;
    # 调用
    call p_max(2,2,@m);
    # 删除
    drop procedure p_max;
    

    题目八:定义一个存储过程,初始变量值为5,不断减1,当变量值为0时停止。

    create procedure p_sub()
    begin
    	declare a int default 5;
    	while a > 0 do
    		set a = a - 1;
    	end while;
    	select a;
    end;
    
    call p_sub();
    

    题目九:定义一个存储过程,输入一个值,如果大于0,则不断减1,当变量值为0时停止。(用repeart)

    create procedure p_repeat(in number int)
    begin
    	repeat
    		while number > 0 do
    			set number = number - 1;
    		end while;
    		select number;
    		until number = 0
    	end repeat;
    end;
    call p_repeat(6);
    

    题目十
    创建一个存储过程p_insert1,作用是向student表中插入一行数据(‘091101’, ‘陶伟’, ‘男’, NULL,NULL,NULL, ‘Cs010901’)。再创建另外一个存储过程p_insert2,接收一个数值,让背后在p_insert2中调用p_insert1,如果输入的值是0,将091101号同学改名为刘英,如果输入值是1,删除091101这个同学

    create procedure p_insert1()
    begin
    	insert into student values('091101', '陶伟', '男', NULL,NULL,NULL, 'Cs010901');
    end;
    
    call p_insert1();
    
    create procedure p_insert2(in a int)
    begin
    	call p_insert1();
    		if a = 0 then 
    			update student set StudentName = '刘英' where StudentID = '091101';
    		elseif b = 1 then 
    			delete from student where StudentID = '091101';
    		end if;
    end;
    
    call p_insert2(0);
    
    drop procedure p_insert1;
    drop procedure p_insert2;
    

    实践题目十,需要用到异常机制的处理,上面的代码目前是由问题的,待我理解透彻之后,将代码放在下面,进行剖析。

    四、异常处理

    异常处理机制的应用
    那么看到上面的代码是有问题的,我们可以通过异常处理机制来处理这样的问题。

    定义条件和处理程序:
    条件和处理程序是MySQL提供的一种异常处理机制,定义条件是事先定义程序执行过程中可能会遇到的问题;定义处理程序是定义在遇到问题时执行的相应处理方法,并且保证存储过程和在遇到问题时不终止。

    注意:数值类型的错误代码不要使用0,因为0表示成功而不是错误;字符串类型的错误代码不要使用’00’,因为’00’表示成功而不是错误。

    在MySQL中定义条件使用DECLARE…CONDITION语句,其语法形式如下:

    DECLARE condition_name CONDITION FOR [condition_type];
    
    • mysql_error_code:表示数值类型错误代码。
    • sqlstate_value:表示长度为5的字符串类型错误代码。

    在这里插入图片描述
    在这里插入图片描述

    create procedure p_insert1()
    begin
    	insert into student values('091101', '陶伟', '男', NULL,NULL,NULL, 'Cs010901');
    end;
    
    call p_insert1();
    
    create procedure p_insert2(in a int)
    begin
    	declare continue handler for 1062 set @info='can not find';
    	call p_insert1();
    		if a = 0 then 
    			update student set StudentName = '刘英' where StudentID = '091101';
    		elseif a = 1 then 
    			delete from student where StudentID = '091101';
    		end if;
    end;
    
    call p_insert2(1);
    
    select * from student;
    
    drop procedure p_insert1;
    drop procedure p_insert2; 
    

    五、游标

    游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制,游标相当于一个指针,可以遍历结果集。

    5.1 定义游标

    在MySQL中,使用DECLARE关键字来定义游标,其语法形式如下:

    DECLARE cursor_name CURSOR FOR select_statement
    

    下面的定义符合一个游标声明:

    declare xs_cur1 cursor   for
    
      	select 学号,姓名,性别,出生日期,总学分
    
    ​    from student
    
    ​    where 专业名 = '计算机';
    

    5.2 打开游标

    声明游标后,要使用游标从中提取数据,就必须先打开游标。在MySQL中,使用OPEN语句打开游标,其格式为:

    OPEN cursor_name
    

    5.3 使用游标

    使用游标的关键字是FETCH,其语法形式如下:

    FETCH cursor_name INTO var_name [, var_name]

    5.4 关闭游标

    关闭游标的关键字为CLOSE,其语法形式如下:

    CLOSE cursor_name
    

    5.5 实践

    不使用MySQL语句中的count函数,自定义统计数据表的行数

        create procedure compute (out number integer)
        begin
    	    declare xh char(20);
    	    declare found boolean default true;
    	    declare number_xs cursor for
    	    select studentid from grade;
    	    declare continue handler for not found
    		    set found=false;
    		    set number=0;
    	    open number_xs;
    	    fetch number_xs into xh;
    		while found do
    		    set number=number+1;
    		    fetch number_xs into xh;
    	    end while;
    	    close number_xs;
        end
    

    六、课前练习以及实验题

    6.1 课前练习

    1. 创建一个存储过程,输入课程号,输出该课程不及格人数

    create procedure p_num(in cid char(8),out num int)
    begin
    	select count(*) into num from grade 
    	where grade.CourseID = cid and grade < 60;
    	select @a;
    end;
    
    call p_num('Dp010001',@a);
    
    
    drop procedure p_num;
    

    在这里插入图片描述
    2. 在grade表中加入一个新列grade_level,通过存储过程输入学号和课程号,得到该门课该同学的成绩,60分以下不及格,60分-80及格,80往上,优秀,根据成绩推断对应的等级放在该条选课记录的grade_level中,并输出“XX同学XX课程及格/不及格/优秀”\

    alter table grade add grade_level char(10);
    
    create procedure t_level(in sid char(20),in cid char(20),out result char(30))
    begin
    declare score int;
    	select grade into score from grade
    	where studentid=sid and courseid=cid;
    	if score<60
    		then update grade set grade_level = "不及格" where studentid=sid and courseid=cid;
    		set result = concat(sid,"同学",cid,"课程不及格");
    	elseif score>=60 and score<80 
    		then update grade set grade_level = "及格" where studentid=sid and courseid=cid;
    		set result = concat(sid,"同学",cid,"课程及格");
    	else
    		update grade set grade_level = "优秀" where studentid=sid and courseid=cid;
    		set result = concat(sid,"同学",cid,"课程优秀");
    	end if;
    end;
    
    select * from grade;
    drop procedure t_level;	#删除存储过程
    
    call t_level("St0109010001","Dp010001",@res);
    select @res;
    
    

    3. 3.创建一个存储过程p_insert1,作用是向student表中插入一行数据(‘091101’, ‘陶伟’, ‘男’, NULL,NULL,NULL, ‘Cs010901’)。再创建另外一个存储过程p_insert2,接收一个数值,让背后在p_insert2中调用p_insert1,如果输入的值是0,将091101号同学改名为刘英,如果输入值是1,删除091101这个同学

    create procedure p_insert1()
    begin
    	insert into student values('091101', '陶伟', '男', NULL,NULL,NULL, 'Cs010901');
    end;
    
    call p_insert1();
    
    create procedure p_insert2(in a int)
    begin
    	declare continue handler for 1062 set @info='can not find';
    	call p_insert1();
    		if a = 0 then 
    			update student set StudentName = '刘英' where StudentID = '091101';
    		elseif a = 1 then 
    			delete from student where StudentID = '091101';
    		end if;
    end;
    
    
    
    call p_insert2(1);
    
    select * from student;
    
    drop procedure p_insert1;
    drop procedure p_insert2; 
    
    

    4. 在grade表中加入一个新列grade_level,通过存储过程给每一个成绩加入其等级放在grade_level列中,60分以下不及格,60分-80及格,80往上,优秀。

    create procedure p_alllevel()
    begin
    	declare sid,cid varchar(20);
    	declare score int;
    	# 定义如果遇到错误,则使用boolean来判断是否中断
    	declare found boolean default true;
    	declare gLevel cursor for
    		# 定义grade_level游标遍历范围
    		select studentid,courseid,grade from grade;
    	# 异常处理
    	declare continue handler for not found 
    		set found = false;
    	open gLevel;
    	fetch gLevel into sid,cid,score;
    	while found do
    		if score<60
    			then update grade set grade_level = "不及格" where studentid=sid and courseid=cid;
    		elseif score>=60 and score<80 
    			then update grade set grade_level = "及格" where studentid=sid and courseid=cid;
    		else
    			update grade set grade_level = "优秀" where studentid=sid and courseid=cid;
    		end if;
    		fetch gLevel into sid,cid,score;
    	end while;
    	close gLevel;
    end;
    
    call p_alllevel();
    select * from grade;
    drop procedure p_alllevel;
    
    
    

    6.2 实验题

    1. 创建存储过程scg,返回所有学生的学号,所选课程号,成绩并调用该存储过程
    create procedure scg()
    begin
    	select studentid,courseid,grade from grade;
    end;
    
    call scg();
    drop procedure scg;
    
    1. 创建存储过程avg_grade,查询整个成绩表的平均分,若平均分大于85,输出该分数,若平均分小于85,输出‘继续努力‘
    create procedure avg_grade(out result char(20))
    begin
    	declare avg int;
    	select avg(grade) into avg from grade;
    	if avg>=85 then
    		set result = avg;
    	elseif avg<85 then 
    		set result = "继续努力";
    	else 
    		set result = "出现错误";
    	end if;
    	select result;
    end;
    
    call avg_grade(@res);
    drop procedure avg_grade;
    
    1. 创建存储过程student_grade,返回某一的学生某一课程的分数,并调用该存储过程。(该题要用out参数)
    create procedure student_grade(in sid char(20),in cid char(20),out res int)
    begin
    	select grade from grade
    	where studentid = sid and courseid = cid;
    end;
    
    select * from grade; 
    call student_grade('St0109010001','Dp010003',@res);
    
    drop procedure student_grade;
    
    
    
    1. 若60分以下为不及格,60-80是良好,80-100是优秀,建立一个存储过程p_count_grade,输入课程名,计算该课程每个分数段各有多少人.(结果如图)
      在这里插入图片描述
    # 普通方法实现
    select coursename,(
    	case when grade<60 then  "不及格"
    	when grade<80 then  "良好"
    	else "优秀" end) as "成绩评价",count(*) AS 人数
    from grade as g ,course as co
    where g.courseid = co.CourseID
    and CourseName = "JAVA程序设计"
    group by coursename,成绩评价;
    
    
    # 存储过程
    create procedure p_count_grade(in coname varchar(20))
    BEGIN
    	select coursename,(
    		case when grade<60 then  "不及格"
    				 when grade<80 then  "良好"
    		else "优秀" end) as "成绩评价",
    	count(*) as 人数
    	from grade as g ,course as co
    	where g.courseid = co.CourseID
    	and CourseName = coname
    	group by coursename,成绩评价;
    END;
    
    CALL p_count_grade("JAVA程序设计")
    
    select * from course;
    
    drop procedure p_count_grade;
    
    1. 创建存储过程grade_change,在该存储过程中调用存储过程student_grade(第3小题),若该名同学成绩大于60,则将该成绩加20分储存在grade表中并输出修改成功,如果小于60分,
      则删除该成绩记录并输出修改成功。创建完成后,调用该存储过程,将两种结果都展示一遍
    create procedure grade_change(out m double,out n double,in sid varchar(20),in cid varchar(20))
    begin
    	call student_grade(@sc,sid,cid);
    	IF @sc>60 then
    		set n = @sc+20;
    		select "修改成功";
      elseif @sc<=60 then
    		delete from grade where  studentid = sid;
    		select "修改成功";
    	end if;
    end;
    
    call grade_change(@a,@b,'St0109010002','Dp010001');
    select @a,@b;
    drop procedure grade_change;
    
    
    1. 创建一个存储过程proce_inout,输入一个数字,如果该数字大于70,则不断减5,直到小于70,如果小于等于70,则不断加5,直到大于70,然后输出处理后的数字(该存储过程只能用一个参数)
    create procedure proce_inout(in num int)
    begin
    	if (num>70) then 
    		while num > 70 do
    			set num = num -5;
    		end while;
    	elseif (num<=70) then
    		while num<=70 do
    			set num = num + 5;
    		end while;
    	end if;
    	select num;
    end;
    
    call proce_inout(79);
    
    drop procedure proce_inout;
    
    
    1. 在grade表中新建一列绩点列列名为level,然后创建一个存储过程,查询每个同学每门课分数并使用游标做如下处理,如果分数大于80分,写入绩点为4,如果获得60-80分,绩点为2,小于60,绩点为0,完成后,输出每个同学的总绩点为多少。
    alter table grade add g_level int;
    select * from grade;
    create procedure score_level()
    begin
    	declare sid,cid varchar(20);
    	declare score int;
    	declare found boolean default true;
    	declare gLevel cursor for
    		# 定义游标遍历范围
    		select studentid,courseid,grade from grade;
    		# 异常处理
    		declare continue handler for not found
    			set found = false;
    		open gLevel;
    		fetch gLevel into sid,cid,score;
    		while found do
    		if score<60
    			then update grade set g_level = 0 where studentid=sid and courseid=cid;
    		elseif score>=60 and score<80 
    			then update grade set g_level = 2 where studentid=sid and courseid=cid;
    		else
    			update grade set g_level = 4 where studentid=sid and courseid=cid;
    		end if;
    		# 使用游标
    		fetch gLevel into sid,cid,score;
    		# 结束循环
    		end while;
    		# 关闭游标
    		close gLevel;
    	
    	select studentid,sum(g_level) from grade group by StudentID;
    end;
    
    call score_level();
    
    select * from grade;
    
    drop procedure score_level;
    
    

    如果你也是爱好编程的小伙伴,欢迎关注我的博客,一键三连,即可解锁我的更多文章!
    一名在校大学生的菜鸟编程之路,热爱创造,热爱学习,热爱分享!

    展开全文
  • 5 图像邻域和块操作

    千次阅读 2017-01-03 11:23:35
    在很多图像处理过程中,对图像分块操作而不是同时处理整幅图像方法是非常通用而且有效,尤其是在后面章节中将要介绍图像滤波和图像形态学操作中有很重要应用。相比全图像操作,图像分块操作至少有以下 3 个...

            在很多图像处理过程中,对图像分块操作而不是同时处理整幅图像的方法是非常通用而且有效的,尤其是在后面章节中将要介绍的图像滤波和图像形态学操作中有很重要的应用。相比全图像操作,图像分块操作至少有以下 3 个优点:

    更多MATLAB图像处理视频请点击  http://study.163.com/course/courseMain.htm?courseId=1003594013

                • 节省运算时占用的存储空间;
                • 降低计算的复杂性,提高处理速度;
                • 充分考虑图像的局部特性。
            本节将会结合图像块操作的类型,介绍几个通用的图像块操作函数。这些块操作函数通常需要指定图像块的大小和对图像块进行特定处理的功能函数。图像块操作的类型有两种:

         • 非重叠块操作(distinct block)
         • 滑动邻域操作(sliding neighborhood)

            这两种操作都是基于一个图像块的整体操作,按照指定的图像处理功能函数得到仅涉及该图像块的计算结果,而且,在对原图像进行块操作时,都可以根据需要指定不同大小的矩形块。然而,不同的是,非重叠块操作对原图像的划分不存在重叠区域,而且在对某一图像块进行处理后,得到的是对应输出图像中同样大小的图像块;滑动邻域操作是基于像素级的操作模式,以原图像某像素点为中心,以指定大小的图像块作为该像素点的邻域,对该像素点的整个邻域进行处理,每次处理后仅得到输出图像中对应像素点的值,而不是一个图像块的计算结果,而且,接下来不改变邻域的大小,仅仅移动邻域的中心像素位置,从而计算出所有的输出图像像素值,在这一过程中相邻图像邻域很明显有重叠区域。


    1.非重叠图像块操作

          非重叠图像块的定义将图像的数据矩阵划分为同样大小的矩形区域,不同的图像块在图像上面排列,相互之间没有重叠。它的排列顺序是从左上角开始。如果图像不能恰好被划分,则在图像的右、下部对其补零。如图所示,一个 15×30 的图像按照 4×8 的图像块进行划分,结果在图像的右边补了两列“0”,在图像的下边补了一行“0”。

        另外,对于一些特别的图像处理操作,可能还需要进行一些特别的图像块划分,即包含有“重叠(Overlap)”定义区域的非重叠(Distinct)图像块划分方式,


      图中阴影区域表示对图像块进行补“0”操作。


               MATLAB 提供了一个通用的非重叠图像块操作函数 blkproc,其语法格式为:

              B = blkproc(A,[m n],fun)
              B = blkproc(A,[m n],fun,P1,P2,⋯)

              B = blkproc(A,[m n],[mborder nborder],fun,⋯)
              B = blkproc(A,’indexed’,⋯)

              B = blkproc(A,[m n],fun)其中[m n]表示按 m×n 的图像块划分对图像 A 做运算,fun 为运算函数,其形式为 y=fun(x),x 表示被操作的图像块。

              B=blkproc(A,[m n],fun,Pl,P2,⋯)指定 fun 中除 x 以外的其他参数 P1、P2、⋯⋯
              B=blkproc[A,[m n],[mborder nborder],fun,⋯]指定图像块的扩展边界 mborder 和 nborder,使得实际操作的图像块大小为(m+2*mborder)*(n+2*nborder)。如图 3-13 所示的包含有“重叠(Overlap)”定义区域的非重叠(Distinct)图像块划分方式,阴影部分即为扩展边界大小,在该图中,扩展边界[mborder nborder]为[1 2]。

              B = blkproc(A,’indexed’,⋯)表示被处理图像 A 为索引色图像。


      例:

     B=imread('C:\Users\Administrator\Desktop\picture\MATLAB图像处理\part5\1.jpg');
    fun=inline('std2(x)*ones(size(x))');
    A=rgb2gray(B);      %将rgb图转换为灰度图
    I1=blkproc(A,[3 3],[2 2],fun);
    I2=blkproc(A,[3 3],fun);
    I3=blkproc(A,[5 5],fun);
    figure,imshow(A),title('原图像');
    figure,imshow(I1),title('I1');
    figure,imshow(I1,[]),title('I1');
    figure,imshow(I2,[]),title('I2');
    figure,imshow(I3,[]),title('I3');




    2.滑动领域操作

       在MATLAB中,滑动领域是一个像素集,像素集包含的元素由中心像素的位置决定。滑动邻域操作一次只处理一个图像像素。当操作从图像矩阵的一个位置移动到另一个位置时,滑动邻域也以相同的方向运动,其示意图如图所示。

    图 中的滑动邻域是一个 2×3 的矩阵,黑点表示中心像素。对于 m×n 的滑动邻域来说,中心像素的位置是:

     floor([(m+1)/2, (n+1)/2])
    其中,floor 表示对其参数的每一个分量向下就近取整,因此,对于 2×2 邻域,其中心就是(1,1),图 3-15中 2×3 滑动邻域的中心就是(1, 2)。

      在 MATLAB 中进行滑动邻域操作的具体步骤如下:
    (1)选择像素;
    (2)确定该像素的滑动邻域;
    (3)调用合适的函数对滑动邻域中的元素进行计算;
    (4)将计算结果作为输出图像中对应像素的值;
    (5)重复计算,遍及图像中的所有像素。

    MATLAB 工具箱提供了一个通用的滑动邻域操作函数 nlfilter。利用 nlfilter 函数可以实现滑动邻域的移动操作,并把待处理图像、邻域大小和一个处理函数(返回值为标量)作为参数,返回与输入图像大小相同的图像作为输出结果。其语法格式为:

        B = nlfilter(A,[m n],fun)
        B = nlfilter(A,[m n],fun,P1,P2,⋯)
        B = nlfilter(A,’indexed’,⋯)

        B = nlfilter(A,[m n],fun)表示对图像 A 进行操作得到图像 B,其中,[m n]表示滑动邻域的大小为 m×n,fun 是作用于图像邻域上的处理函数。函数 fun 的输入是大小为 m×n 的矩阵,返回值是一个标量值。假定 x 表示某一个图像邻域矩阵,c 表示函数 fun 的返回值,则有表达式 c = fun(x),c 就表示对应图像邻域 x 的中心像素的输出值。

    B = nlfilter(A,[m n],fun,P1,P2,⋯)可以传递参数 P1,P2,⋯给函数 fun。
    B = nlfilter(A,’indexed’,⋯)把图像 A 作为索引色图像进行处理,如果图像数据是 double 类型,则对其图像邻域进行填补(Padding)时,对图像以外的区域补“1”,而当图像数据为uint8 类型时,用“0”填补空白区域。

    函数 nlfilter 的参数 fun 可以是一个函数句柄或是一个内联函数,看下面的例子。
    (1)fun 作为一个函数句柄
    B = nlfilter(A,[3 3],@myfun);
    这里,myfun 表示一个 M 文件,其中包含以下语句:
    function scalar = myfun(x)
    scalar = median(x(:));

    (2)fun 作为一个内联函数
    fun=inline(’median(x(:))’);

    例:

    计算输入图像的 3×3 邻域(被处理像素本身和其周边的八个邻域在内的九个像素点)像素值的最大值作为输出像素点的像素值。作为参数的处理函数(最大值函数 max)采用内联函数形式

    B=imread('C:\Users\Administrator\Desktop\picture\MATLAB图像处理\part5\1.jpg');
    >> A=rgb2gray(B);%转换成灰度图像
    >> f=inline('max(x(:))');
    >> J=nlfilter(A,[3 3],f);
    figure,imshow(A),title('原图像');
    figure,imshow(J,[]),title('结果图像');



     所示是在执行上述代码时弹出来的状态条,显示执行的进程,整个计算过程用了大约 1 分钟的时间,处理结果如图  所示。


    下一节的内容会向大家介绍一个快速进行图像块处理的函数,colfilt,比较完成相同处理任务两者耗费的时间差异,表明后者的计算复杂度明显降低。


    3. 图像块处理的快速算法

            前面讲到的非重叠图像块操作和滑动邻域操作都是对原图像进行划分,进而对每个图像块矩阵逐个调用处理函数进行操作。然而,在前面我们举的一个滑动邻域操作的例子,可以看到,为了对一幅 一般的灰度图像执行这一操作,用时大约 1 分钟。可想而知,如果是处理更大的图像,或者是作用更复杂的处理函数,其处理时间会更长。

         为了加快图像块处理的速度,MATLAB 图像处理工具箱提供了一个快速处理函数 colfilt,可以处理非重叠图像块操作和滑动邻域操作。该函数在处理过程中,会首先把要处理的图像块(非重叠块或滑动邻域)重新按列组合成一个临时矩阵,继而对该临时矩阵的每一列(对应着每一个要处理的图像块)调用处理函数。在这一过程中,因为实现了矩阵式操作,大大提高了处理速度,根本没有弹出如上图 所示的状态条,几乎是立刻得到完全一样的计算结果。

        如图所示,(a)表示利用函数 colfilt 对一个6×5 大小的图像进行滑动邻域操作,滑动邻域的大小为 2×3,可以看到,所有要处理的滑动邻域被映射到一个临时矩阵,该矩阵的一列就代表一个滑动邻域,从而得到临时矩阵的大小为 6×30;(b)表示利用函数 colfilt 对一个 6×16 大小的图像进行非重叠图像块操作,非重叠图像块的大小为 4×6,将所要处理的图像块映射到一个临时矩阵,矩阵的一列就代表一个非重叠图像块,从而得到临时矩阵的大小为24×6。


        colfilt 函数的语法格式如下:
       B = colfilt(A,[m n],block_type,fun)
       B = colfilt(A,[m n],block_type,fun,P1,P2,⋯)
       B = colfilt(A,[m n],[mblock nblock],block_type,fun,⋯)
       B = colfilt(A,’indexed’,⋯)

       B = colfilt(A,[m n],block_type,fun)表示对图像A实现快速的以函数fun表示的图像块操作得到输出图像 B,图像块的尺寸为 m×n,block_type 指定了图像块的类型,即

      block_type=’distinct’,非重叠图像块
      block_type=’sliding’,滑动邻域
      fun 为运算函数,其形式为 y=fun(x)。
      B = colfilt(A,[m n],block_type,fun,P1,P2,⋯)指定 fun 中除 x 以外的其他参数 P1、P2、⋯。

      B = colfilt(A,[m n],[mblock nblock],block_type,fun,⋯)是一种节省内存的处理方法。从colfilt 生产临时矩阵的方法,读者可以看到该种处理方法将比寻常的图像块操作方式占用更多的内存。为了既提高图像块处理的速度,又能节省占用的内存,该语句实现把图像 A 分割成 mblock×nblock 大小的子图像,同时只是对该子图像进行操作,通过多次调用函数 fun 来完成整幅图像的操作。这种方法的计算结果与不进行子图像分割是完全一样的。

     例:同样采用在滑动邻域操作中介绍的例子来说明函数 colfilt 的应用,并比较处理速度。

    B=imread('C:\Users\Administrator\Desktop\picture\MATLAB图像处理\part5\1.jpg');
    A=rgb2gray(B);%转换成灰度图像
    f=inline('max(x)');

    J=colfilt(A,[3 3],'sliding',f);
    figure,imshow(A),title('原图像');
    figure,imshow(J,[]),title('J');

     

     注意:这里 f 的定义是 max(x),而不是 max(x(:))。这是因为在原图像中,每个像素的邻域已经被排列成列向量。

    同样,也可以利用 colfilt 函数对输入图像进行’distinct’类型的块操作,即非重叠图像块操作,处理速度也会比 blkproc 函数要快。然而,colfilt 并不能完全代替 blkproc 函数,而是有以下限制:

       • 输出图像必须和输入图像的尺寸相同;
      • 图像块不能有重叠,即不能处理包含有“重叠(Overlap)”定义区域的“非重叠(Distinct)”图像块划分方式。
    在这两种限制情况之外,就只能调用 blkproc 函数。


    更多MATLAB图像处理视频请点击  http://study.163.com/course/courseMain.htm?courseId=1003594013

    展开全文
  • JSP具有以下的优点: 1、将业务层与表示层分离:使用JSP技术,网络开发人员可充分使用HTML来设计页面显示部分(如字体颜色等),并使用JSP指令或者JAVA程序片段来生成网页上的动态内容; 2、能够跨平台:JSP支持绝...
  • ISP 功能的优点: ①在系统中编程不需要移出微控制器。 ②不需并行编程器仅需用P15,P16 和P17,这三个IO 仅仅是下载程序的时 候使用,并不影响程序的使用。 ③结合上位机软件免费就可实现PC 对其编程硬件电路连接...
  • 在本次的课程设计中我觉得应该注意的加强对触发器和存储过程的操作能力。虽然不是很难,但很多细小的问题需要认真的对待,稍有不注意问题就会在具体的应用程序调试过程中出现,这要求我们在实践的过程中除了要了塌实...
  • 引用类型和原始类型具有不同特征和用法,它们包括:大小和速度问题,这种类型以哪种类型数据结构存储,当引用类型和原始类型用作某个类实例数据时所指定缺省值。对象引用实例变量缺省值为 null,而原始...
  • ASP.NET网页代码模型及生命周期

    热门讨论 2009-07-28 14:22:11
    在ASP.NET中,网页包含视图状态来保存用户的信息,视图状态在页面发回到自身时,跨页过程存储和用户自己的页面的特定值,视图状态的优点如下所示。 q 不需要任何服务器资源。 q 在默认情况下,对控件启用状态的数据...
  • 基于ASP学生信息档案管理系统毕业论文及源码

    千次下载 热门讨论 2007-06-08 12:20:16
    作为计算机应用的一部分,使用计算机对学生档案信息进行管理,具备手工管理所无法比拟的优点。例如:检索迅速、查找方便、可靠性高、存储量大、保密性好、寿命长、成本低等,这些优点能够极大地提高学生档案...
  • "封装"是 OOP 语言的优点之一。把一个对象的数据加以包装并置于其方法的保护之下 称为封装。所谓封装就是对数据的隐藏。封装实现了把数据和操作这些数据的代码包装成为 一个对象(即离散的部件),而数据和操作细节...
  • 你可以用以下的语句来为一个数值赋值: $a = 1234; # 十进制数 $a = -123; # 负数 $a = 0123; # 八进制数 (等于十进制数83) $a = 0x12; # 十六进制数(等于十进制数18) $a = 1.234; # 浮点数"双精度数" $a = 1.2...
  • <div><p>最近关于 Serverless 讨论越来越多。看似与前端关系不大 Serverless,其实早已和前端有了颇深渊源,...比如阿里云对象存储触发器,是基于阿里云 OSS 产品存取等事件触发;...
  • C#微软培训教材(高清PDF)

    千次下载 热门讨论 2009-07-30 08:51:17
    17.2 文件存储管理 .217 17.3 读 写 文 件 .222 17.4 异步文件操作 .227 17.5 小 结 .234 第十八章 高 级 话 题 .235 18.1 注册表编程 .235 18.2 在 C #代码中调用 C++和 VB 编写组件 .240 18.3 版 ...
  • 3.13.5 Oracle与存储系统兼容性 72 第4章 使用SQL*Plus和Oracle企业管理器 73 4.1 启动SQL*Plus会话 73 4.1.1 设置环境 73 4.1.2 从命令行启动SQL*Plus会话 74 4.1.3 用CONNECT命令进行连接 75 4.1.4...
  • (46) 面向对象的设计方法与传统的的面向过程的方法有本质不同,它的基本原理是(C) A. 模拟现实世界中不同事物之间的联系 B. 强调模拟现实世界中的算法而不强调概念 C. 使用现实世界的概念抽象地思考问题从而自然地...
  • 设计算法都是自己编写,可能存在不是最优算法情况。 二、设计正文 1 需求分析  建立一个用户可以自由交易平台,通过ajax实现局部刷新,实现网站更具人性化,具有更良好互动。以下是总体需求 1.1 通过...
  • C#微软培训资料

    2014-01-22 14:10:17
    17.2 文件存储管理 .217 17.3 读 写 文 件 .222 17.4 异步文件操作 .227 17.5 小 结 .234 第十八章 高 级 话 题 .235 18.1 注册表编程 .235 18.2 在 C #代码中调用 C++和 VB 编写组件 .240 18.3 版 ...
  • 软件工程知识点

    2012-12-02 21:34:25
    增量模型结合了瀑布模型与原型进化模型的优点。在整体上按照瀑布模型的流程实施开发,以方便对项目的管理。但在软件的实际创建中,则将软件系统按功能分解为许多增量构件逐个地创建与交付,直到全部构件创建完毕,并...
  • 《数据结构 1800题》

    热门讨论 2012-12-27 16:52:03
    11. 顺序存储方式的优点存储密度大,且插入、删除运算效率高。( )【上海海运学院 1999 一、1(1分)】 12. 数据结构的基本操作的设置的最重要的准则是,实现应用程序与存储结构的独立。( ) 【华南理工大学 2002...
  • 算法执行过程中所需要的存储空间 (22) 下列关于栈叙述中正确是______。(D) A. 在栈中只能插入数据 B. 在栈中只能删除数据 C. 栈是先进先出线性表 D. 栈是先进后出线性表 (23) 在深度为5满二*树中,叶子...
  • 书中继承了《sql必知必会》的优点,在精练然而透彻地阐述了数据库基础理论之后,紧贴实战需要,很快转向数据检索,逐步深入各种复杂的内容,包括联结的使用、子查询、基于全文本的搜索等等。对于每个知识点,都给出...
  • •兼有段式和页式管理的优点,系统复杂和开销增大,一般在大型机器上才使用。 第五章文件管理 1、文件管理任务与功能 任务:把存储、检索、共享和保护文件的手段,提供给操作系统本身和用户,以达到方便...
  • 过程的逆过程为解密,即将该编码信息转化为其原来的形式的过程。 DES算法, DES(Data Encryption Standard)是由IBM公司在1970年以后发展起来的,于1976年11月被美国政府采用,DES随后被美国国家标准局和美国国家...

空空如也

空空如也

1 2 3 4 5
收藏数 99
精华内容 39
关键字:

以下不是存储过程的优点