精华内容
下载资源
问答
  • MySQL创建存储过程

    千次阅读 2021-02-03 07:36:36
    在开发过程中,经常会遇到重复使用某一个功能的情况,为此,MySQL引入了存储过程...大大减少数据库开发人员的工作量创建存储过程使用CREATE PROCEDURE语句CREATE PROCEDURE sp_name([proc_parameter])[characteri...

    在开发过程中,经常会遇到重复使用某一个功能的情况,为此,MySQL引入了存储过程

    存储过程

    就是一条或多条SQL语句的集合,当对数据库进行一系列复杂操作时,存储过程可以将这些复杂操纵,封装成一个代码块,以便重复使用,大大减少数据库开发人员的工作量

    创建存储过程

    使用CREATE PROCEDURE语句

    CREATE PROCEDURE sp_name([proc_parameter])

    [characteristics……]routine_body

    参数说明

    CREATE PROCEDURE,创建存储过程的关键字

    Sp_name,为存储过程的名称

    Proc_parameter,为指定存储过程的参数列表,参数列表的形式,如下

    [IN|OUT|INOUT]param_name type

    参数列表说明

    IN,表示输入参数

    OUT,表示输出参数

    INOUT,表示既可以输入,也可以输出

    Param_name,表示参数名称

    type,表示参数的类型,可以是MySQL数据库中的任意类型

    在创建存储过程的语法格式中,characteristics用于指定存储过程的特性,取值如下

    LANGUAGE SQL

    说明,routine_doby部分,是由SQL语句组成的,当前系统支持的语言为SQL,SQL是LANGUAGE的唯一值

    [NOT] DETERMINISTIC

    指明存储过程执行的结果是否正确,DETERMINISTIC表示结果是正确的,每次执行存储过程时,相同的输入可能得到不同的输出,如果没有指定任意一个值,默认为NOT DETERMINISTIC

    {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}

    指明子程序使用SQL语句的限制

    CONTAINS SQL,表示子程序包含SQL语句,但是,不包含读写数据的语句

    NO SQL,表示子程序不包含SQL语句

    READS SQL DATA,说明子程序,包含读写数据的语句

    MODIFIES SQL DATA,表示子程序包含写数据的语句

    默认情况下,系统会指定为CONTAINS SQL

    SQL SECURITY{DEFINER | INVOKER}

    指明,谁有权限来执行

    DEFINER,表示只有定义者才能执行

    INVOKER,表示拥有权限的调用者可以执行

    默认情况下,系统指定为DEFINER

    COMMENT’string’

    注释信息,用来表示存储过程

    Routine_body,是SQL代码的内容,可以用BEGIN……END来表示SQL代码的开始和结束

    首先,在数据库chapter06中,创建表student

    创建student表之后,插入4条记录

    0818b9ca8b590ca3270a3433284dd417.png

    创建一个查看student表的存储过程

    0818b9ca8b590ca3270a3433284dd417.png

    参数说明

    DELIMITER //

    作用,将MySQL的结束符设置为//,因为,MySQL默认的语句结束符号为分号;,为了避免与存储过程中,SQL语句结束符相冲突,需要使用DELIMTER改变存储过程的结束符,并且,以END //结束存储过程

    存储过程,定义完毕之后,再使用DELIMITER,恢复默认结束符 DELIMITER,可以指定其他符号作为结束符 注意,DELIMITER与设置的结束符之间,一定要有一个空格,否则设置无效

    展开全文
  • navicat怎么创建存储过程

    千次阅读 2021-01-18 21:08:43
    navicat怎么创建存储过程?下面就为大家详细介绍一下其中涉及到的操作。1、使用Navicat Premium打开创建函数向导,操作:连接名——数据库——函数——新建函数2、选择过程——输入存储过程参数——完成(这一步可以...

    fafefb82e61c1f99d4e798d57923ab68.png

    navicat怎么创建存储过程?下面就为大家详细介绍一下其中涉及到的操作。

    1、使用Navicat Premium打开创建函数向导,操作:连接名——数据库——函数——新建函数

    6f4a9b1ef829869f3cf1c27733a7b16a.png

    2、选择过程——输入存储过程参数——完成(这一步可以不填写参数,编写存储过程代码的时候设置参数)

    40e794587d5541968a0e39a95c3ec260.png

    b83779a9e5df7f095e1302a2f2ad7b9b.png

    3、按照要求完成存储过程代码编写BEGIN

    DECLARE t_error INTEGER DEFAULT 0;

    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;

    # 保证数据一致性 开启事务

    START TRANSACTION;

    # 获取需同步数据的时间节点(3个月前的第一天)

    # 即当前日期 2018-07-10 @upmonth 日期 2018-04-01 8

    SET @upmonth= DATE_ADD(CURDATE() - DAY (CURDATE()) + 1, INTERVAL - 3 MONTH);

    # 迁移数据语句

    SET @sqlstr=CONCAT(‘INSERT INTO fd_aseet_record_back_3_6

    SELECT * FROM fd_asset_record WHERE type in (3, 6) AND calendar_date < ?‘);

    # 删除数据语句

    SET @delsqlstr=CONCAT(‘DELETE FROM fd_asset_record WHERE type in (3, 6) AND calendar_date < ?‘);

    #执行数据迁移

    PREPARE _fddatamt FROM @sqlstr;

    EXECUTE _fddatamt USING @upmonth;

    DEALLOCATE PREPARE _fddatamt;

    #执行迁移后的数据删除

    PREPARE _fddatadel FROM @delsqlstr;

    EXECUTE _fddatadel USING @upmonth;

    DEALLOCATE PREPARE _fddatadel;

    IF t_error = 1 THEN

    ROLLBACK; #语句异常-回滚

    ELSE

    COMMIT; #提交事务

    END IF;

    END

    4、保存——输入存储过程名——确定

    9557b283bc0c4d3cbf0ed532bba3b08c.png

    5、选择存储过程名——运行函数——查看结果

    242d730369ded3061ab7094d28c0a329.png

    29ab8ad4cb80d5fef53c32ae963a0faf.png

    扩展资料

    存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。主要分为一下几类。

    1系统存储过程

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

    2本地存储过程

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

    3临时存储过程

    分为两种存储过程:

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

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

    4远程存储过程

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

    5扩展存储过程

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

    展开全文
  • Oracle创建存储过程实例

    千次阅读 2018-04-24 23:15:05
    认识存储过程和函数 存储过程和函数也是一种PL/SQL块,是存入数据库的PL/SQL块。但存储过程和函数不同于已经介绍过的PL/SQL程序,我们通常把PL/SQL程序称为无名块,而存储过程和函数是以命名的方式存储于数据库中...

    认识存储过程和函数

    存储过程和函数也是一种PL/SQL块,是存入数据库的PL/SQL块。但存储过程和函数不同于已经介绍过的PL/SQL程序,我们通常把PL/SQL程序称为无名块,而存储过程和函数是以命名的方式存储于数据库中的。和PL/SQL程序相比,存储过程有很多优点,具体归纳如下:

    • 存储过程和函数以命名的数据库对象形式存储于数据库当中。存储在数据库中的优点是很明显的,因为代码不保存在本地,用户可以在任何客户机上登录到数据库,并调用或修改代码。
    • 存储过程和函数可由数据库提供安全保证,要想使用存储过程和函数,需要有存储过程和函数的所有者的授权,只有被授权的用户或创建者本身才能执行存储过程或调用函数。
    • 存储过程和函数的信息是写入数据字典的,所以存储过程可以看作是一个公用模块,用户编写的PL/SQL程序或其他存储过程都可以调用它(但存储过程和函数不能调用PL/SQL程序)。一个重复使用的功能,可以设计成为存储过程,比如:显示一张工资统计表,可以设计成为存储过程;一个经常调用的计算,可以设计成为存储函数;根据雇员编号返回雇员的姓名,可以设计成存储函数。
    • 像其他高级语言的过程和函数一样,可以传递参数给存储过程或函数,参数的传递也有多种方式。存储过程可以有返回值,也可以没有返回值,存储过程的返回值必须通过参数带回;函数有一定的数据类型,像其他的标准函数一样,我们可以通过对函数名的调用返回函数值。

         存储过程和函数需要进行编译,以排除语法错误,只有编译通过才能调用。

      创建和删除存储过程

      创建存储过程,需要有CREATE PROCEDURE或CREATE ANY PROCEDURE的系统权限。该权限可由系统管理员授予。创建一个存储过程的基本语句如下:

      CREATE [OR REPLACE] PROCEDURE 存储过程名[(参数[IN|OUT|IN OUT] 数据类型…)]

      {AS|IS}

      [说明部分]

      BEGIN

      可执行部分

      [EXCEPTION

      错误处理部分]

      END [过程名];

      其中:

      可选关键字OR REPLACE 表示如果存储过程已经存在,则用新的存储过程覆盖,通常用于存储过程的重建。

      参数部分用于定义多个参数(如果没有参数,就可以省略)。参数有三种形式:IN、OUT和IN OUT。如果没有指明参数的形式,则默认为IN。

      关键字AS也可以写成IS,后跟过程的说明部分,可以在此定义过程的局部变量。

      编写存储过程可以使用任何文本编辑器或直接在SQLPlus环境下进行,编写好的存储过程必须要在SQLPlus环境下进行编译,生成编译代码,原代码和编译代码在编译过程中都会被存入数据库。编译成功的存储过程就可以在Oracle环境下进行调用了。

      一个存储过程在不需要时可以删除。删除存储过程的人是过程的创建者或者拥有DROP ANY PROCEDURE系统权限的人。删除存储过程的语法如下:

      DROP PROCEDURE 存储过程名;

      如果要重新编译一个存储过程,则只能是过程的创建者或者拥有ALTER ANY PROCEDURE系统权限的人。语法如下:

      ALTER PROCEDURE 存储过程名 COMPILE;

      执行(或调用)存储过程的人是过程的创建者或是拥有EXECUTE ANY PROCEDURE系统权限的人或是被拥有者授予EXECUTE权限的人。执行的方法如下:

      方法1:

      EXECUTE 模式名.存储过程名[(参数…)];

      方法2:

      BEGIN

      模式名.存储过程名[(参数…)];

      END;

      传递的参数必须与定义的参数类型、个数和顺序一致(如果参数定义了默认值,则调用时可以省略参数)。参数可以是变量、常量或表达式,用法参见下一节。

      如果是调用本账户下的存储过程,则模式名可以省略。要调用其他账户编写的存储过程,则模式名必须要添加。

      以下是一个生成和调用简单存储过程的训练。注意要事先授予创建存储过程的权限。

      【训练1】  创建一个显示雇员总人数的存储过程。

      步骤1:登录SCOTT账户(或学生个人账户)。

      步骤2:在SQL*Plus输入区中,输入以下存储过程:
    Sql代码 复制代码
    1. CREATE OR REPLACE PROCEDURE EMP_COUNT   
    2. AS  
    3. V_TOTAL NUMBER(10);   
    4. BEGIN  
    5.  SELECT COUNT(*) INTO V_TOTAL FROM EMP;   
    6.  DBMS_OUTPUT.PUT_LINE('雇员总人数为:'||V_TOTAL);   
    7. END;  
    1. CREATE OR REPLACE PROCEDURE EMP_COUNT  
    2. AS  
    3. V_TOTAL NUMBER(10);  
    4. BEGIN  
    5.  SELECT COUNT(*) INTO V_TOTAL FROM EMP;  
    6.  DBMS_OUTPUT.PUT_LINE('雇员总人数为:'||V_TOTAL);  
    7. END;  

    步骤3:按“执行”按钮进行编译。
    如果存在错误,就会显示:
    警告: 创建的过程带有编译错误。
    如果存在错误,对脚本进行修改,直到没有错误产生。
    如果编译结果正确,将显示:
    Sql代码 复制代码
    1. 过程已创建。  
    1. 过程已创建。  

    步骤4:调用存储过程,在输入区中输入以下语句并执行:
    Sql代码 复制代码
    1. EXECUTE EMP_COUNT;  
    1. EXECUTE EMP_COUNT;  

    显示结果为:
    Sql代码 复制代码
    1. 雇员总人数为:14   
    2.         PL/SQL 过程已成功完成。  
    1. 雇员总人数为:14  
    2.         PL/SQL 过程已成功完成。  

    说明:在该训练中,V_TOTAL变量是存储过程定义的局部变量,用于接收查询到的雇员总人数。
    注意:在SQL*Plus中输入存储过程,按“执行”按钮是进行编译,不是执行存储过程。
      如果在存储过程中引用了其他用户的对象,比如表,则必须有其他用户授予的对象访问权限。一个存储过程一旦编译成功,就可以由其他用户或程序来引用。但存储过程或函数的所有者必须授予其他用户执行该过程的权限。
    存储过程没有参数,在调用时,直接写过程名即可。
    【训练2】  在PL/SQL程序中调用存储过程。
    步骤1:登录SCOTT账户。
    步骤2:授权STUDENT账户使用该存储过程,即在SQL*Plus输入区中,输入以下的命令:
    Sql代码 复制代码
    1. GRANT EXECUTE ON EMP_COUNT TO STUDENT  
    1. GRANT EXECUTE ON EMP_COUNT TO STUDENT  

    Sql代码 复制代码
    1. 授权成功。  
    1. 授权成功。  

    步骤3:登录STUDENT账户,在SQL*Plus输入区中输入以下程序:
    Sql代码 复制代码
    1. SET SERVEROUTPUT ON  
    2.         BEGIN  
    3.         SCOTT.EMP_COUNT;   
    4.         END;  
    1. SET SERVEROUTPUT ON  
    2.         BEGIN  
    3.         SCOTT.EMP_COUNT;  
    4.         END;  

    步骤4:执行以上程序,结果为:
    Sql代码 复制代码
    1. 雇员总人数为:14   
    2.         PL/SQL 过程已成功完成。   
    1. 雇员总人数为:14  
    2.         PL/SQL 过程已成功完成。   

      说明:在本例中,存储过程是由SCOTT账户创建的,STUDEN账户获得SCOTT账户的授权后,才能调用该存储过程。
      注意:在程序中调用存储过程,使用了第二种语法。
    【训练3】  编写显示雇员信息的存储过程EMP_LIST,并引用EMP_COUNT存储过程。
    步骤1:在SQL*Plus输入区中输入并编译以下存储过程:
    Sql代码 复制代码
    1. CREATE OR REPLACE PROCEDURE EMP_LIST   
    2.         AS  
    3.          CURSOR emp_cursor IS    
    4.         SELECT empno,ename FROM emp;   
    5.         BEGIN  
    6. FOR Emp_record IN emp_cursor LOOP      
    7.     DBMS_OUTPUT.PUT_LINE(Emp_record.empno||Emp_record.ename);   
    8.         END LOOP;   
    9.         EMP_COUNT;   
    10.         END;  
    1. CREATE OR REPLACE PROCEDURE EMP_LIST  
    2.         AS  
    3.          CURSOR emp_cursor IS   
    4.         SELECT empno,ename FROM emp;  
    5.         BEGIN  
    6. FOR Emp_record IN emp_cursor LOOP     
    7.     DBMS_OUTPUT.PUT_LINE(Emp_record.empno||Emp_record.ename);  
    8.         END LOOP;  
    9.         EMP_COUNT;  
    10.         END;  

    执行结果:
    Sql代码 复制代码
    1. 过程已创建。  
    1. 过程已创建。  

    步骤2:调用存储过程,在输入区中输入以下语句并执行:
    Sql代码 复制代码
    1. EXECUTE EMP_LIST  
    1. EXECUTE EMP_LIST  

    显示结果为:
    Sql代码 复制代码
    1. 7369SMITH   
    2. 7499ALLEN   
    3. 7521WARD   
    4. 7566JONES   
    5.             执行结果:   
    6.         雇员总人数为:14   
    7.         PL/SQL 过程已成功完成。  
    1. 7369SMITH  
    2. 7499ALLEN  
    3. 7521WARD  
    4. 7566JONES  
    5.             执行结果:  
    6.         雇员总人数为:14  
    7.         PL/SQL 过程已成功完成。  

    说明:以上的EMP_LIST存储过程中定义并使用了游标,用来循环显示所有雇员的信息。然后调用已经成功编译的存储过程EMP_COUNT,用来附加显示雇员总人数。通过EXECUTE命令来执行EMP_LIST存储过程。
    【练习1】编写显示部门信息的存储过程DEPT_LIST,要求统计出部门个数。
    参数传递
    参数的作用是向存储过程传递数据,或从存储过程获得返回结果。正确的使用参数可以大大增加存储过程的灵活性和通用性。
    参数的类型有三种,如下所示。
    Sql代码 复制代码
    1. IN  定义一个输入参数变量,用于传递参数给存储过程   
    2. OUT 定义一个输出参数变量,用于从存储过程获取数据   
    3. IN OUT  定义一个输入、输出参数变量,兼有以上两者的功能  
    1. IN  定义一个输入参数变量,用于传递参数给存储过程  
    2. OUT 定义一个输出参数变量,用于从存储过程获取数据  
    3. IN OUT  定义一个输入、输出参数变量,兼有以上两者的功能  

    参数的定义形式和作用如下:
    参数名 IN 数据类型 DEFAULT 值;
    定义一个输入参数变量,用于传递参数给存储过程。在调用存储过程时,主程序的实际参数可以是常量、有值变量或表达式等。DEFAULT 关键字为可选项,用来设定参数的默认值。如果在调用存储过程时不指明参数,则参数变量取默认值。在存储过程中,输入变量接收主程序传递的值,但不能对其进行赋值。
    参数名 OUT 数据类型;
    定义一个输出参数变量,用于从存储过程获取数据,即变量从存储过程中返回值给主程序。
    在调用存储过程时,主程序的实际参数只能是一个变量,而不能是常量或表达式。在存储过程中,参数变量只能被赋值而不能将其用于赋值,在存储过程中必须给输出变量至少赋值一次。
    参数名 IN OUT 数据类型 DEFAULT 值;
    定义一个输入、输出参数变量,兼有以上两者的功能。在调用存储过程时,主程序的实际参数只能是一个变量,而不能是常量或表达式。DEFAULT 关键字为可选项,用来设定参数的默认值。在存储过程中,变量接收主程序传递的值,同时可以参加赋值运算,也可以对其进行赋值。在存储过程中必须给变量至少赋值一次。
    如果省略IN、OUT或IN OUT,则默认模式是IN。
    【训练1】  编写给雇员增加工资的存储过程CHANGE_SALARY,通过IN类型的参数传递要增加工资的雇员编号和增加的工资额。
    步骤1:登录SCOTT账户。
      步骤2:在SQL*Plus输入区中输入以下存储过程并执行:
    Sql代码 复制代码
    1. CREATE OR REPLACE PROCEDURE CHANGE_SALARY(P_EMPNO IN NUMBER DEFAULT 7788,P_RAISE NUMBER DEFAULT 10)   
    2.         AS  
    3.          V_ENAME VARCHAR2(10);   
    4. V_SAL NUMBER(5);   
    5.         BEGIN  
    6.         SELECT ENAME,SAL INTO V_ENAME,V_SAL FROM EMP WHERE EMPNO=P_EMPNO;   
    7.          UPDATE EMP SET SAL=SAL+P_RAISE WHERE EMPNO=P_EMPNO;   
    8.          DBMS_OUTPUT.PUT_LINE('雇员'||V_ENAME||'的工资被改为'||TO_CHAR(V_SAL+P_RAISE));   
    9. COMMIT;   
    10.         EXCEPTION   
    11.          WHEN OTHERS THEN  
    12.         DBMS_OUTPUT.PUT_LINE('发生错误,修改失败!');   
    13.         ROLLBACK;   
    14.         END;  
    1. CREATE OR REPLACE PROCEDURE CHANGE_SALARY(P_EMPNO IN NUMBER DEFAULT 7788,P_RAISE NUMBER DEFAULT 10)  
    2.         AS  
    3.          V_ENAME VARCHAR2(10);  
    4. V_SAL NUMBER(5);  
    5.         BEGIN  
    6.         SELECT ENAME,SAL INTO V_ENAME,V_SAL FROM EMP WHERE EMPNO=P_EMPNO;  
    7.          UPDATE EMP SET SAL=SAL+P_RAISE WHERE EMPNO=P_EMPNO;  
    8.          DBMS_OUTPUT.PUT_LINE('雇员'||V_ENAME||'的工资被改为'||TO_CHAR(V_SAL+P_RAISE));  
    9. COMMIT;  
    10.         EXCEPTION  
    11.          WHEN OTHERS THEN  
    12.         DBMS_OUTPUT.PUT_LINE('发生错误,修改失败!');  
    13.         ROLLBACK;  
    14.         END;  

    执行结果为:
    Sql代码 复制代码
    1. 过程已创建。  
    1. 过程已创建。  

    步骤3:调用存储过程,在输入区中输入以下语句并执行:
    Sql代码 复制代码
    1. EXECUTE CHANGE_SALARY(7788,80)  
    1. EXECUTE CHANGE_SALARY(7788,80)  

    显示结果为:
    Sql代码 复制代码
    1. 雇员SCOTT的工资被改为3080   
    1. 雇员SCOTT的工资被改为3080   

    说明:从执行结果可以看到,雇员SCOTT的工资已由原来的3000改为3080。
    参数的值由调用者传递,传递的参数的个数、类型和顺序应该和定义的一致。如果顺序不一致,可以采用以下调用方法。如上例,执行语句可以改为:
     EXECUTE CHANGE_SALARY(P_RAISE=>80,P_EMPNO=>7788);
      可以看出传递参数的顺序发生了变化,并且明确指出了参数名和要传递的值,=>运算符左侧是参数名,右侧是参数表达式,这种赋值方法的意义较清楚。
    【练习1】创建插入雇员的存储过程INSERT_EMP,并将雇员编号等作为参数。
    在设计存储过程的时候,也可以为参数设定默认值,这样调用者就可以不传递或少传递参数了。
    【训练2】  调用存储过程CHANGE_SALARY,不传递参数,使用默认参数值。
    在SQL*Plus输入区中输入以下命令并执行:
    Sql代码 复制代码
    1. EXECUTE CHANGE_SALARY  
    1. EXECUTE CHANGE_SALARY  

    显示结果为:
    Sql代码 复制代码
    1. 雇员SCOTT的工资被改为3090   
    1. 雇员SCOTT的工资被改为3090   

    说明:在存储过程的调用中没有传递参数,而是采用了默认值7788和10,即默认雇员号为7788,增加的工资为10。
    【训练3】  使用OUT类型的参数返回存储过程的结果。
    步骤1:登录SCOTT账户。
    步骤2:在SQL*Plus输入区中输入并编译以下存储过程:
    Sql代码 复制代码
    1. CREATE OR REPLACE PROCEDURE EMP_COUNT(P_TOTAL OUT NUMBER)   
    2.         AS  
    3.         BEGIN  
    4.         SELECT COUNT(*) INTO P_TOTAL FROM EMP;   
    5.         END;  
    1. CREATE OR REPLACE PROCEDURE EMP_COUNT(P_TOTAL OUT NUMBER)  
    2.         AS  
    3.         BEGIN  
    4.         SELECT COUNT(*) INTO P_TOTAL FROM EMP;  
    5.         END;  

    执行结果为:
    Sql代码 复制代码
    1. 过程已创建。  
    1. 过程已创建。  

    步骤3:输入以下程序并执行:
    Sql代码 复制代码
    1. DECLARE  
    2.         V_EMPCOUNT NUMBER;   
    3.         BEGIN  
    4.         EMP_COUNT(V_EMPCOUNT);   
    5.         DBMS_OUTPUT.PUT_LINE('雇员总人数为:'||V_EMPCOUNT);   
    6.         END;  
    1. DECLARE  
    2.         V_EMPCOUNT NUMBER;  
    3.         BEGIN  
    4.         EMP_COUNT(V_EMPCOUNT);  
    5.         DBMS_OUTPUT.PUT_LINE('雇员总人数为:'||V_EMPCOUNT);  
    6.         END;  

    显示结果为:
    Sql代码 复制代码
    1. 雇员总人数为:14   
    2.         PL/SQL 过程已成功完成。  
    1. 雇员总人数为:14  
    2.         PL/SQL 过程已成功完成。  

        说明:在存储过程中定义了OUT类型的参数P_TOTAL,在主程序调用该存储过程时,传递了参数V_EMPCOUNT。在存储过程中的SELECT...INTO...语句中对P_TOTAL进行赋值,赋值结果由V_EMPCOUNT变量带回给主程序并显示。
    以上程序要覆盖同名的EMP_COUNT存储过程,如果不使用OR REPLACE选项,就会出现以下错误:
    Sql代码 复制代码
    1. ERROR 位于第 1 行:   
    2.         ORA-00955: 名称已由现有对象使用。  
    1. ERROR 位于第 1 行:  
    2.         ORA-00955: 名称已由现有对象使用。  

    【练习2】创建存储过程,使用OUT类型参数获得雇员经理名。
    【训练4】  使用IN OUT类型的参数,给电话号码增加区码。
    步骤1:登录SCOTT账户。
    步骤2:在SQL*Plus输入区中输入并编译以下存储过程:
    Sql代码 复制代码
    1. CREATE OR REPLACE PROCEDURE ADD_REGION(P_HPONE_NUM IN OUT VARCHAR2)   
    2.         AS  
    3.         BEGIN  
    4.          P_HPONE_NUM:='0755-'||P_HPONE_NUM;   
    5.         END;  
    1. CREATE OR REPLACE PROCEDURE ADD_REGION(P_HPONE_NUM IN OUT VARCHAR2)  
    2.         AS  
    3.         BEGIN  
    4.          P_HPONE_NUM:='0755-'||P_HPONE_NUM;  
    5.         END;  

    执行结果为:
    Sql代码 复制代码
    1. 过程已创建。  
    1. 过程已创建。  

    步骤3:输入以下程序并执行:
    Sql代码 复制代码
    1. SET SERVEROUTPUT ON  
    2. DECLARE  
    3. V_PHONE_NUM VARCHAR2(15);   
    4. BEGIN  
    5. V_PHONE_NUM:='26731092';   
    6. ADD_REGION(V_PHONE_NUM);   
    7. DBMS_OUTPUT.PUT_LINE('新的电话号码:'||V_PHONE_NUM);   
    8. END;  
    1. SET SERVEROUTPUT ON  
    2. DECLARE  
    3. V_PHONE_NUM VARCHAR2(15);  
    4. BEGIN  
    5. V_PHONE_NUM:='26731092';  
    6. ADD_REGION(V_PHONE_NUM);  
    7. DBMS_OUTPUT.PUT_LINE('新的电话号码:'||V_PHONE_NUM);  
    8. END;  

    显示结果为:
    Sql代码 复制代码
    1. 新的电话号码:0755-26731092   
    2.         PL/SQL 过程已成功完成。  
    1. 新的电话号码:0755-26731092  
    2.         PL/SQL 过程已成功完成。  

    说明:变量V_HPONE_NUM既用来向存储过程传递旧电话号码,也用来向主程序返回新号码。新的号码在原来基础上增加了区号0755和-。
    创建和删除存储函数
      创建函数,需要有CREATE PROCEDURE或CREATE ANY PROCEDURE的系统权限。该权限可由系统管理员授予。创建存储函数的语法和创建存储过程的类似,即
    CREATE [OR REPLACE] FUNCTION 函数名[(参数[IN] 数据类型...)]
    RETURN 数据类型
    {AS|IS}
    [说明部分]
    BEGIN
    可执行部分
    RETURN (表达式)
    [EXCEPTION
        错误处理部分]
    END [函数名];
    其中,参数是可选的,但只能是IN类型(IN关键字可以省略)。
    在定义部分的RETURN 数据类型,用来表示函数的数据类型,也就是返回值的类型,此部分不可省略。
    在可执行部分的RETURN(表达式),用来生成函数的返回值,其表达式的类型应该和定义部分说明的函数返回值的数据类型一致。在函数的执行部分可以有多个RETURN语句,但只有一个RETURN语句会被执行,一旦执行了RETURN语句,则函数结束并返回调用环境。
    一个存储函数在不需要时可以删除,但删除的人应是函数的创建者或者是拥有DROP ANY PROCEDURE系统权限的人。其语法如下:
    DROP FUNCTION 函数名;
    重新编译一个存储函数时,编译的人应是函数的创建者或者拥有ALTER ANY PROCEDURE系统权限的人。重新编译一个存储函数的语法如下:
    ALTER PROCEDURE 函数名 COMPILE;
    函数的调用者应是函数的创建者或拥有EXECUTE ANY PROCEDURE系统权限的人,或是被函数的拥有者授予了函数执行权限的账户。函数的引用和存储过程不同,函数要出现在程序体中,可以参加表达式的运算或单独出现在表达式中,其形式如下:
    变量名:=函数名(...)
    【训练1】  创建一个通过雇员编号返回雇员名称的函数GET_EMP_NAME。
    步骤1:登录SCOTT账户。
    步骤2:在SQL*Plus输入区中输入以下存储函数并编译:
    Sql代码 复制代码
    1. CREATE OR REPLACE FUNCTION GET_EMP_NAME(P_EMPNO NUMBER DEFAULT 7788)   
    2.         RETURN VARCHAR2   
    3.         AS  
    4.          V_ENAME VARCHAR2(10);   
    5.         BEGIN  
    6.         ELECT ENAME INTO V_ENAME FROM EMP WHERE EMPNO=P_EMPNO;   
    7. RETURN(V_ENAME);   
    8. EXCEPTION   
    9.  WHEN NO_DATA_FOUND THEN  
    10.   DBMS_OUTPUT.PUT_LINE('没有该编号雇员!');   
    11.   RETURN (NULL);   
    12.  WHEN TOO_MANY_ROWS THEN  
    13.   DBMS_OUTPUT.PUT_LINE('有重复雇员编号!');   
    14.   RETURN (NULL);   
    15.  WHEN OTHERS THEN  
    16.   DBMS_OUTPUT.PUT_LINE('发生其他错误!');   
    17.   RETURN (NULL);   
    18. END;  
    1. CREATE OR REPLACE FUNCTION GET_EMP_NAME(P_EMPNO NUMBER DEFAULT 7788)  
    2.         RETURN VARCHAR2  
    3.         AS  
    4.          V_ENAME VARCHAR2(10);  
    5.         BEGIN  
    6.         ELECT ENAME INTO V_ENAME FROM EMP WHERE EMPNO=P_EMPNO;  
    7. RETURN(V_ENAME);  
    8. EXCEPTION  
    9.  WHEN NO_DATA_FOUND THEN  
    10.   DBMS_OUTPUT.PUT_LINE('没有该编号雇员!');  
    11.   RETURN (NULL);  
    12.  WHEN TOO_MANY_ROWS THEN  
    13.   DBMS_OUTPUT.PUT_LINE('有重复雇员编号!');  
    14.   RETURN (NULL);  
    15.  WHEN OTHERS THEN  
    16.   DBMS_OUTPUT.PUT_LINE('发生其他错误!');  
    17.   RETURN (NULL);  
    18. END;  

    步骤3:调用该存储函数,输入并执行以下程序:
    Sql代码 复制代码
    1. BEGIN  
    2.         DBMS_OUTPUT.PUT_LINE('雇员7369的名称是:'|| GET_EMP_NAME(7369));   
    3.          DBMS_OUTPUT.PUT_LINE('雇员7839的名称是:'|| GET_EMP_NAME(7839));   
    4.         END;  
    1. BEGIN  
    2.         DBMS_OUTPUT.PUT_LINE('雇员7369的名称是:'|| GET_EMP_NAME(7369));  
    3.          DBMS_OUTPUT.PUT_LINE('雇员7839的名称是:'|| GET_EMP_NAME(7839));  
    4.         END;  

    显示结果为:
    Sql代码 复制代码
    1. 雇员7369的名称是:SMITH   
    2.         雇员7839的名称是:KING   
    3.         PL/SQL 过程已成功完成。  
    1. 雇员7369的名称是:SMITH  
    2.         雇员7839的名称是:KING  
    3.         PL/SQL 过程已成功完成。  

    说明:函数的调用直接出现在程序的DBMS_OUTPUT.PUT_LINE语句中,作为字符串表达式的一部分。如果输入了错误的雇员编号,就会在函数的错误处理部分输出错误信息。试修改雇员编号,重新运行调用部分。
    【练习1】创建一个通过部门编号返回部门名称的存储函数GET_DEPT_NAME。
       【练习2】将函数的执行权限授予STUDENT账户,然后登录STUDENT账户调用。
    存储过程和函数的查看
    可以通过对数据字典的访问来查询存储过程或函数的有关信息,如果要查询当前用户的存储过程或函数的源代码,可以通过对USER_SOURCE数据字典视图的查询得到。USER_SOURCE的结构如下:
    Sql代码 复制代码
    1. DESCRIBE USER_SOURCE  
    1. DESCRIBE USER_SOURCE  

    结果为:
    Sql代码 复制代码
    1. 名称                                      是否为空? 类型   
    2.         ------------------------------------------------------------- ------------- -----------------------  
    3.  NAME                                               VARCHAR2(30)   
    4.  TYPE                                               VARCHAR2(12)   
    5.  LINE                                               NUMBER   
    6.  TEXT                                               VARCHAR2(4000)  
    1. 名称                                      是否为空? 类型  
    2.         ------------------------------------------------------------- ------------- -----------------------  
    3.  NAME                                               VARCHAR2(30)  
    4.  TYPE                                               VARCHAR2(12)  
    5.  LINE                                               NUMBER  
    6.  TEXT                                               VARCHAR2(4000)  

      说明:里面按行存放着过程或函数的脚本,NAME是过程或函数名,TYPE 代表类型(PROCEDURE或FUNCTION),LINE是行号,TEXT 为脚本。
    【训练1】  查询过程EMP_COUNT的脚本。
    在SQL*Plus中输入并执行如下查询:
    Sql代码 复制代码
    1. select TEXT  from user_source WHERE NAME='EMP_COUNT';  
    1. select TEXT  from user_source WHERE NAME='EMP_COUNT';  

    结果为:
    Sql代码 复制代码
    1. TEXT   
    2. --------------------------------------------------------------------------------  
    3. PROCEDURE EMP_COUNT(P_TOTAL OUT NUMBER)   
    4. AS  
    5. BEGIN  
    6.  SELECT COUNT(*) INTO P_TOTAL FROM EMP;   
    7. END;  
    1. TEXT  
    2. --------------------------------------------------------------------------------  
    3. PROCEDURE EMP_COUNT(P_TOTAL OUT NUMBER)  
    4. AS  
    5. BEGIN  
    6.  SELECT COUNT(*) INTO P_TOTAL FROM EMP;  
    7. END;  

    【训练2】  查询过程GET_EMP_NAME的参数。
    在SQL*Plus中输入并执行如下查询:
    Sql代码 复制代码
    1. DESCRIBE GET_EMP_NAME  
    1. DESCRIBE GET_EMP_NAME  

    结果为:
    Sql代码 复制代码
    1. FUNCTION GET_EMP_NAME RETURNS VARCHAR2   
    2.         参数名称            类型          输入/输出默认值?   
    3.         ----------------------------------------- ----------------------------------- ----------------- -------------  
    4.         P_EMPNO             NUMBER(4) IN     DEFAULT  
    1. FUNCTION GET_EMP_NAME RETURNS VARCHAR2  
    2.         参数名称            类型          输入/输出默认值?  
    3.         ----------------------------------------- ----------------------------------- ----------------- -------------  
    4.         P_EMPNO             NUMBER(4) IN     DEFAULT  

    【训练3】  在发生编译错误时,显示错误。
    Sql代码 复制代码
    1. SHOW ERRORS  
    1. SHOW ERRORS  

    以下是一段编译错误显示:
    Sql代码 复制代码
    1. LINE/COL ERROR   
    2.         ------------- -----------------------------------------------------------------  
    3.         4/2       PL/SQL: SQL Statement ignored   
    4.         4/36      PLS-00201: 必须说明标识符 'EMPP'  
    1. LINE/COL ERROR  
    2.         ------------- -----------------------------------------------------------------  
    3.         4/2       PL/SQL: SQL Statement ignored  
    4.         4/36      PLS-00201: 必须说明标识符 'EMPP'  

      说明:查询一个存储过程或函数是否是有效状态(即编译成功),可以使用数据字典USER_OBJECTS的STATUS列。
    【训练4】  查询EMP_LIST存储过程是否可用:
    Sql代码 复制代码
    1. SELECT STATUS FROM USER_OBJECTS WHERE OBJECT_NAME='EMP_LIST';  
    1. SELECT STATUS FROM USER_OBJECTS WHERE OBJECT_NAME='EMP_LIST';  

    结果为:
    Sql代码 复制代码
    1. STATUS   
    2.         ------------  
    3.         VALID  
    1. STATUS  
    2.         ------------  
    3.         VALID  

    说明:VALID表示该存储过程有效(即通过编译),INVALID表示存储过程无效或需要重新编译。当Oracle调用一个无效的存储过程或函数时,首先试图对其进行编译,如果编译成功则将状态置成VALID并执行,否则给出错误信息。
    当一个存储过程编译成功,状态变为VALID,会不会在某些情况下变成INVALID。结论是完全可能的。比如一个存储过程中包含对表的查询,如果表被修改或删除,存储过程就会变成无效INVALID。所以要注意存储过程和函数对其他对象的依赖关系。
    如果要检查存储过程或函数的依赖性,可以通过查询数据字典USER_DENPENDENCIES来确定,该表结构如下:
    Sql代码 复制代码
    1. DESCRIBE USER_DEPENDENCIES;  
    1. DESCRIBE USER_DEPENDENCIES;  

    结果:
    Sql代码 复制代码
    1. 名称                     是否为空? 类型   
    2.         -------------------------------------------------------------- ------------- ----------------------------  
    3.          NAME            NOT NULL   VARCHAR2(30)   
    4.          TYPE                       VARCHAR2(12)   
    5.         REFERENCED_OWNER                                VARCHAR2(30)   
    6.  REFERENCED_NAME                                VARCHAR2(64)   
    7.  REFERENCED_TYPE                                VARCHAR2(12)   
    8. REFERENCED_LINK_NAME                            VARCHAR2(128)   
    9.         SCHEMAID                                        NUMBER   
    10.          DEPENDENCY_TYPE                                VARCHAR2(4)  
    1. 名称                     是否为空? 类型  
    2.         -------------------------------------------------------------- ------------- ----------------------------  
    3.          NAME            NOT NULL   VARCHAR2(30)  
    4.          TYPE                       VARCHAR2(12)  
    5.         REFERENCED_OWNER                                VARCHAR2(30)  
    6.  REFERENCED_NAME                                VARCHAR2(64)  
    7.  REFERENCED_TYPE                                VARCHAR2(12)  
    8. REFERENCED_LINK_NAME                            VARCHAR2(128)  
    9.         SCHEMAID                                        NUMBER  
    10.          DEPENDENCY_TYPE                                VARCHAR2(4)  

      说明:NAME为实体名,TYPE为实体类型,REFERENCED_OWNER为涉及到的实体拥有者账户,REFERENCED_NAME为涉及到的实体名,REFERENCED_TYPE 为涉及到的实体类型。
    【训练5】  查询EMP_LIST存储过程的依赖性。
    Sql代码 复制代码
    1. SELECT REFERENCED_NAME,REFERENCED_TYPE FROM USER_DEPENDENCIES WHERE NAME='EMP_LIST';  
    1. SELECT REFERENCED_NAME,REFERENCED_TYPE FROM USER_DEPENDENCIES WHERE NAME='EMP_LIST';  

    执行结果:
    Sql代码 复制代码
    1. REFERENCED_NAME                                         REFERENCED_TYPE   
    2.         ------------------------------------------------------------------------------------------ ----------------------------  
    3. STANDARD                                                PACKAGE   
    4.         SYS_STUB_FOR_PURITY_ANALYSIS                            PACKAGE   
    5.         DBMS_OUTPUT                                                 PACKAGE   
    6.         DBMS_OUTPUT                                             SYNONYM   
    7. DBMS_OUTPUT                      NON-EXISTENT   
    8.         EMP                                                         TABLE  
    9.         EMP_COUNT                                                   PROCEDURE  
    1. REFERENCED_NAME                                         REFERENCED_TYPE  
    2.         ------------------------------------------------------------------------------------------ ----------------------------  
    3. STANDARD                                                PACKAGE  
    4.         SYS_STUB_FOR_PURITY_ANALYSIS                            PACKAGE  
    5.         DBMS_OUTPUT                                                 PACKAGE  
    6.         DBMS_OUTPUT                                             SYNONYM  
    7. DBMS_OUTPUT                      NON-EXISTENT  
    8.         EMP                                                         TABLE  
    9.         EMP_COUNT                                                   PROCEDURE  

      说明:可以看出存储过程EMP_LIST依赖一些系统包、EMP表和EMP_COUNT存储过程。如果删除了EMP表或EMP_COUNT存储过程,EMP_LIST将变成无效。
    还有一种情况需要我们注意:如果一个用户A被授予执行属于用户B的一个存储过程的权限,在用户B的存储过程中,访问到用户C的表,用户B被授予访问用户C的表的权限,但用户A没有被授予访问用户C表的权限,那么用户A调用用户B的存储过程是失败的还是成功的呢?答案是成功的。如果读者有兴趣,不妨进行一下实际测试。


    包的概念和组成
    包是用来存储相关程序结构的对象,它存储于数据字典中。包由两个分离的部分组成:包头(PACKAGE)和包体(PACKAGE BODY)。包头是包的说明部分,是对外的操作接口,对应用是可见的;包体是包的代码和实现部分,对应用来说是不可见的黑盒。
    包中可以包含的程序结构如下所示。
    Sql代码 复制代码
    1. 过程(PROCUDURE)   带参数的命名的程序模块   
    2. 函数(FUNCTION)    带参数、具有返回值的命名的程序模块   
    3. 变量(VARIABLE)    存储变化的量的存储单元   
    4. 常量(CONSTANT)    存储不变的量的存储单元   
    5. 游标(CURSOR)  用户定义的数据操作缓存区,在可执行部分使用   
    6. 类型(TYPE)    用户定义的新的结构类型   
    7. 异常(EXCEPTION)   在标准包中定义或由用户自定义,用于处理程序错误  
    1. 过程(PROCUDURE)   带参数的命名的程序模块  
    2. 函数(FUNCTION)    带参数、具有返回值的命名的程序模块  
    3. 变量(VARIABLE)    存储变化的量的存储单元  
    4. 常量(CONSTANT)    存储不变的量的存储单元  
    5. 游标(CURSOR)  用户定义的数据操作缓存区,在可执行部分使用  
    6. 类型(TYPE)    用户定义的新的结构类型  
    7. 异常(EXCEPTION)   在标准包中定义或由用户自定义,用于处理程序错误  

    说明部分可以出现在包的三个不同的部分:出现在包头中的称为公有元素,出现在包体中的称为私有元素,出现在包体的过程(或函数)中的称为局部变量。它们的性质有所不同,如下所示。
    Sql代码 复制代码
    1. 公有元素(PUBLIC)    在包头中说明,在包体中具体定义 在包外可见并可以访问,对整个应用的全过程有效   
    2. 私有元素(PRIVATE)   在包体的说明部分说明  只能被包内部的其他部分访问   
    3. 局部变量(LOCAL) 在过程或函数的说明部分说明   只能在定义变量的过程或函数中使用  
    1. 公有元素(PUBLIC)    在包头中说明,在包体中具体定义 在包外可见并可以访问,对整个应用的全过程有效  
    2. 私有元素(PRIVATE)   在包体的说明部分说明  只能被包内部的其他部分访问  
    3. 局部变量(LOCAL) 在过程或函数的说明部分说明   只能在定义变量的过程或函数中使用  

    在包体中出现的过程或函数,如果需要对外公用,就必须在包头中说明,包头中的说明应该和包体中的说明一致。
    包有以下优点:
    * 包可以方便地将存储过程和函数组织到一起,每个包又是相互独立的。在不同的包中,过程、函数都可以重名,这解决了在同一个用户环境中命名的冲突问题。
    * 包增强了对存储过程和函数的安全管理,对整个包的访问权只需一次授予。
      * 在同一个会话中,公用变量的值将被保留,直到会话结束。
    * 区分了公有过程和私有过程,包体的私有过程增加了过程和函数的保密性。
    * 包在被首次调用时,就作为一个整体被全部调入内存,减少了多次访问过程或函数的I/O次数。
    创建包和包体
    包由包头和包体两部分组成,包的创建应该先创建包头部分,然后创建包体部分。创建、删除和编译包的权限同创建、删除和编译存储过程的权限相同。
    创建包头的简要语句如下:
    CREATE [OR REPLACE] PACKAGE 包名
    {IS|AS}
    公有变量定义
    公有类型定义
    公有游标定义
    公有异常定义
    函数说明
    过程说明
    END;
    创建包体的简要语法如下:
    CREATE [OR REPLACE] PACKAGE BODY 包名
    {IS|AS}
    私有变量定义
    私有类型定义
    私有游标定义
    私有异常定义
    函数定义
    过程定义
    END;
    包的其他操作命令包括:
    删除包头:
    DROP PACKAGE 包头名
    删除包体:
    DROP PACKAGE BODY 包体名
    重新编译包头:
    ALTER PACKAGE 包名 COMPILE PACKAGE
    重新编译包体:
    ALTER PACKAGE 包名 COMPILE PACKAGE BODY
    在包头中说明的对象可以在包外调用,调用的方法和调用单独的过程或函数的方法基本相同,惟一的区别就是要在调用的过程或函数名前加上包的名字(中间用“.”分隔)。但要注意,不同的会话将单独对包的公用变量进行初始化,所以不同的会话对包的调用属于不同的应用。
    系统包
    Oracle预定义了很多标准的系统包,这些包可以在应用中直接使用,比如在训练中我们使用的DBMS_OUTPUT包,就是系统包。PUT_LINE是该包的一个函数。常用系统包下所示。
    Sql代码 复制代码
    1. DBMS_OUTPUT 在SQL*Plus环境下输出信息   
    2. DBMS_DDL    编译过程函数和包   
    3. DBMS_SESSION    改变用户的会话,初始化包等   
    4. DBMS_TRANSACTION    控制数据库事务   
    5. DBMS_MAIL   连接Oracle*Mail   
    6. DBMS_LOCK   进行复杂的锁机制管理   
    7. DBMS_ALERT  识别数据库事件告警   
    8. DBMS_PIPE   通过管道在会话间传递信息   
    9. DBMS_JOB    管理Oracle的作业   
    10. DBMS_LOB    操纵大对象   
    11. DBMS_SQL    执行动态SQL语句  
    1. DBMS_OUTPUT 在SQL*Plus环境下输出信息  
    2. DBMS_DDL    编译过程函数和包  
    3. DBMS_SESSION    改变用户的会话,初始化包等  
    4. DBMS_TRANSACTION    控制数据库事务  
    5. DBMS_MAIL   连接Oracle*Mail  
    6. DBMS_LOCK   进行复杂的锁机制管理  
    7. DBMS_ALERT  识别数据库事件告警  
    8. DBMS_PIPE   通过管道在会话间传递信息  
    9. DBMS_JOB    管理Oracle的作业  
    10. DBMS_LOB    操纵大对象  
    11. DBMS_SQL    执行动态SQL语句  

    包的应用
    在SQL*Plus环境下,包和包体可以分别编译,也可以一起编译。如果分别编译,则要先编译包头,后编译包体。如果在一起编译,则包头写在前,包体在后,中间用“/”分隔。
    可以将已经存在的存储过程或函数添加到包中,方法是去掉过程或函数创建语句的CREATE OR REPLACE部分,将存储过程或函数复制到包体中 ,然后重新编译即可。
       如果需要将私有过程或函数变成共有过程或函数的话,将过程或函数说明部分复制到包头说明部分,然后重新编译就可以了。
    【训练1】  创建管理雇员信息的包EMPLOYE,它具有从EMP表获得雇员信息,修改雇员名称,修改雇员工资和写回EMP表的功能。
    步骤1:登录SCOTT账户,输入以下代码并编译:
    Sql代码 复制代码
    1. CREATE OR REPLACE PACKAGE EMPLOYE --包头部分   
    2.         IS  
    3.  PROCEDURE SHOW_DETAIL;    
    4.  PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER);    
    5.  PROCEDURE SAVE_EMPLOYE;    
    6.  PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2);    
    7. PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER);    
    8.         END EMPLOYE;   
    9.         /   
    10.         CREATE OR REPLACE PACKAGE BODY EMPLOYE --包体部分   
    11.         IS  
    12.  EMPLOYE EMP%ROWTYPE;   
    13.         -------------- 显示雇员信息 ---------------  
    14.         PROCEDURE SHOW_DETAIL   
    15.         AS  
    16.         BEGIN  
    17. DBMS_OUTPUT.PUT_LINE(‘----- 雇员信息 -----’);     
    18.         DBMS_OUTPUT.PUT_LINE('雇员编号:'||EMPLOYE.EMPNO);   
    19.         DBMS_OUTPUT.PUT_LINE('雇员名称:'||EMPLOYE.ENAME);   
    20.           DBMS_OUTPUT.PUT_LINE('雇员职务:'||EMPLOYE.JOB);   
    21.          DBMS_OUTPUT.PUT_LINE('雇员工资:'||EMPLOYE.SAL);   
    22.          DBMS_OUTPUT.PUT_LINE('部门编号:'||EMPLOYE.DEPTNO);   
    23.         END SHOW_DETAIL;   
    24. ----------------- 从EMP表取得一个雇员 --------------------  
    25.          PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER)   
    26.         AS  
    27.         BEGIN  
    28.         SELECT * INTO EMPLOYE FROM EMP WHERE    EMPNO=P_EMPNO;   
    29.         DBMS_OUTPUT.PUT_LINE('获取雇员'||EMPLOYE.ENAME||'信息成功');   
    30.          EXCEPTION   
    31.          WHEN OTHERS THEN  
    32.            DBMS_OUTPUT.PUT_LINE('获取雇员信息发生错误!');   
    33.         END GET_EMPLOYE;   
    34. ---------------------- 保存雇员到EMP表 --------------------------  
    35.         PROCEDURE SAVE_EMPLOYE   
    36.         AS  
    37.         BEGIN  
    38.         UPDATE EMP SET ENAME=EMPLOYE.ENAME, SAL=EMPLOYE.SAL WHERE EMPNO=   
    39.     EMPLOYE.EMPNO;   
    40.      DBMS_OUTPUT.PUT_LINE('雇员信息保存完成!');   
    41.         END SAVE_EMPLOYE;   
    42. ---------------------------- 修改雇员名称 ------------------------------  
    43.         PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2)   
    44.          AS  
    45.         BEGIN  
    46.          EMPLOYE.ENAME:=P_NEWNAME;   
    47.          DBMS_OUTPUT.PUT_LINE('修改名称完成!');   
    48.         END CHANGE_NAME;   
    49. ---------------------------- 修改雇员工资 --------------------------  
    50.         PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER)   
    51.         AS  
    52.         BEGIN  
    53.          EMPLOYE.SAL:=P_NEWSAL;   
    54.          DBMS_OUTPUT.PUT_LINE('修改工资完成!');   
    55.         END CHANGE_SAL;   
    56.         END EMPLOYE;  
    1. CREATE OR REPLACE PACKAGE EMPLOYE --包头部分   
    2.         IS  
    3.  PROCEDURE SHOW_DETAIL;   
    4.  PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER);   
    5.  PROCEDURE SAVE_EMPLOYE;   
    6.  PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2);   
    7. PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER);   
    8.         END EMPLOYE;  
    9.         /  
    10.         CREATE OR REPLACE PACKAGE BODY EMPLOYE --包体部分   
    11.         IS  
    12.  EMPLOYE EMP%ROWTYPE;  
    13.         -------------- 显示雇员信息 ---------------  
    14.         PROCEDURE SHOW_DETAIL  
    15.         AS  
    16.         BEGIN  
    17. DBMS_OUTPUT.PUT_LINE(‘----- 雇员信息 -----’);     
    18.         DBMS_OUTPUT.PUT_LINE('雇员编号:'||EMPLOYE.EMPNO);  
    19.         DBMS_OUTPUT.PUT_LINE('雇员名称:'||EMPLOYE.ENAME);  
    20.           DBMS_OUTPUT.PUT_LINE('雇员职务:'||EMPLOYE.JOB);  
    21.          DBMS_OUTPUT.PUT_LINE('雇员工资:'||EMPLOYE.SAL);  
    22.          DBMS_OUTPUT.PUT_LINE('部门编号:'||EMPLOYE.DEPTNO);  
    23.         END SHOW_DETAIL;  
    24. ----------------- 从EMP表取得一个雇员 --------------------  
    25.          PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER)  
    26.         AS  
    27.         BEGIN  
    28.         SELECT * INTO EMPLOYE FROM EMP WHERE    EMPNO=P_EMPNO;  
    29.         DBMS_OUTPUT.PUT_LINE('获取雇员'||EMPLOYE.ENAME||'信息成功');  
    30.          EXCEPTION  
    31.          WHEN OTHERS THEN  
    32.            DBMS_OUTPUT.PUT_LINE('获取雇员信息发生错误!');  
    33.         END GET_EMPLOYE;  
    34. ---------------------- 保存雇员到EMP表 --------------------------  
    35.         PROCEDURE SAVE_EMPLOYE  
    36.         AS  
    37.         BEGIN  
    38.         UPDATE EMP SET ENAME=EMPLOYE.ENAME, SAL=EMPLOYE.SAL WHERE EMPNO=  
    39.     EMPLOYE.EMPNO;  
    40.      DBMS_OUTPUT.PUT_LINE('雇员信息保存完成!');  
    41.         END SAVE_EMPLOYE;  
    42. ---------------------------- 修改雇员名称 ------------------------------  
    43.         PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2)  
    44.          AS  
    45.         BEGIN  
    46.          EMPLOYE.ENAME:=P_NEWNAME;  
    47.          DBMS_OUTPUT.PUT_LINE('修改名称完成!');  
    48.         END CHANGE_NAME;  
    49. ---------------------------- 修改雇员工资 --------------------------  
    50.         PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER)  
    51.         AS  
    52.         BEGIN  
    53.          EMPLOYE.SAL:=P_NEWSAL;  
    54.          DBMS_OUTPUT.PUT_LINE('修改工资完成!');  
    55.         END CHANGE_SAL;  
    56.         END EMPLOYE;  

    步骤2:获取雇员7788的信息:
    Sql代码 复制代码
    1. SET SERVEROUTPUT ON  
    2.         EXECUTE EMPLOYE.GET_EMPLOYE(7788);  
    1. SET SERVEROUTPUT ON  
    2.         EXECUTE EMPLOYE.GET_EMPLOYE(7788);  

    结果为:
    Sql代码 复制代码
    1. 获取雇员SCOTT信息成功   
    2.         PL/SQL 过程已成功完成。  
    1. 获取雇员SCOTT信息成功  
    2.         PL/SQL 过程已成功完成。  

    步骤3:显示雇员信息:
    Sql代码 复制代码
    1. EXECUTE EMPLOYE.SHOW_DETAIL;  
    1. EXECUTE EMPLOYE.SHOW_DETAIL;  

    结果为:
    Sql代码 复制代码
    1. ------------------ 雇员信息 ------------------  
    2.         雇员编号:7788   
    3.         雇员名称:SCOTT   
    4.         雇员职务:ANALYST   
    5.         雇员工资:3000   
    6.         部门编号:20   
    7.         PL/SQL 过程已成功完成。  
    1. ------------------ 雇员信息 ------------------  
    2.         雇员编号:7788  
    3.         雇员名称:SCOTT  
    4.         雇员职务:ANALYST  
    5.         雇员工资:3000  
    6.         部门编号:20  
    7.         PL/SQL 过程已成功完成。  

    步骤4:修改雇员工资:
    Sql代码 复制代码
    1. EXECUTE EMPLOYE.CHANGE_SAL(3800);  
    1. EXECUTE EMPLOYE.CHANGE_SAL(3800);  

    结果为:
    Sql代码 复制代码
    1. 修改工资完成!   
    2.         PL/SQL 过程已成功完成。  
    1. 修改工资完成!  
    2.         PL/SQL 过程已成功完成。  

    步骤5:将修改的雇员信息存入EMP表
    Sql代码 复制代码
    1. EXECUTE EMPLOYE.SAVE_EMPLOYE;  
    1. EXECUTE EMPLOYE.SAVE_EMPLOYE;  

    结果为:
    Sql代码 复制代码
    1. 雇员信息保存完成!   
    2.         PL/SQL 过程已成功完成。  
    1. 雇员信息保存完成!  
    2.         PL/SQL 过程已成功完成。  

    说明:该包完成将EMP表中的某个雇员的信息取入内存记录变量,在记录变量中进行修改编辑,在确认显示信息正确后写回EMP表的功能。记录变量EMPLOYE用来存储取得的雇员信息,定义为私有变量,只能被包的内部模块访问。
      【练习1】为包增加修改雇员职务和部门编号的功能。

    阶段训练
    下面的训练通过定义和创建完整的包EMP_PK并综合运用本章的知识,完成对雇员表的插入、删除等功能,包中的主要元素解释如下所示。
    Sql代码 复制代码
    1. 程序结构    类  型    说    明   
    2. V_EMP_COUNT 公有变量    跟踪雇员的总人数变化,插入、删除雇员的同时修改该变量的值   
    3. INIT    公有过程    对包进行初始化,初始化雇员人数和工资修改的上、下限   
    4. LIST_EMP    公有过程    显示雇员列表   
    5. INSERT_EMP  公有过程    通过编号插入新雇员   
    6. DELETE_EMP  公有过程    通过编号删除雇员   
    7. CHANGE_EMP_SAL  公有过程    通过编号修改雇员工资   
    8. V_MESSAGE   私有变量    存放准备输出的信息   
    9. C_MAX_SAL   私有变量    对工资修改的上限   
    10. C_MIN_SAL   私有变量    对工资修改的下限   
    11. SHOW_MESSAGE    私有过程    显示私有变量V_MESSAGE中的信息   
    12. EXIST_EMP   私有函数    判断某个编号的雇员是否存在,该函数被INSERT_EMP、DELETE_EMP和CHANGE_EMP_SAL等过程调用  
    1. 程序结构    类  型    说    明  
    2. V_EMP_COUNT 公有变量    跟踪雇员的总人数变化,插入、删除雇员的同时修改该变量的值  
    3. INIT    公有过程    对包进行初始化,初始化雇员人数和工资修改的上、下限  
    4. LIST_EMP    公有过程    显示雇员列表  
    5. INSERT_EMP  公有过程    通过编号插入新雇员  
    6. DELETE_EMP  公有过程    通过编号删除雇员  
    7. CHANGE_EMP_SAL  公有过程    通过编号修改雇员工资  
    8. V_MESSAGE   私有变量    存放准备输出的信息  
    9. C_MAX_SAL   私有变量    对工资修改的上限  
    10. C_MIN_SAL   私有变量    对工资修改的下限  
    11. SHOW_MESSAGE    私有过程    显示私有变量V_MESSAGE中的信息  
    12. EXIST_EMP   私有函数    判断某个编号的雇员是否存在,该函数被INSERT_EMP、DELETE_EMP和CHANGE_EMP_SAL等过程调用  

    【训练1】  完整的雇员包EMP_PK的创建和应用。
    步骤1:在SQL*Plus中登录SCOTT账户,输入以下包头和包体部分,按“执行”按钮编译:
    Sql代码 复制代码
    1. CREATE OR REPLACE PACKAGE EMP_PK    
    2.         --包头部分   
    3.         IS  
    4.         V_EMP_COUNT NUMBER(5);                 
    5.         --雇员人数  
    6.         PROCEDURE INIT(P_MAX NUMBER,P_MIN NUMBER);  --初始化  
    7.         PROCEDURE LIST_EMP;                        
    8.         --显示雇员列表  
    9. PROCEDURE INSERT_EMP(P_EMPNO        NUMBER,P_ENAMEVARCHAR2,P_JOB VARCHAR2,   
    10.         P_SAL NUMBER);                         
    11.         --插入雇员  
    12.         PROCEDURE DELETE_EMP(P_EMPNO NUMBER);       --删除雇员  
    13.          PROCEDURE CHANGE_EMP_SAL(P_EMPNO NUMBER,P_SAL NUMBER);    
    14.         --修改雇员工资  
    15.         END EMP_PK;   
    16.         /CREATE OR REPLACE PACKAGE BODY EMP_PK   
    17.          --包体部分   
    18.         IS  
    19.         V_MESSAGE VARCHAR2(50); --显示信息  
    20. V_MAX_SAL NUMBER(7); --工资上限  
    21.         V_MIN_SAL NUMBER(7); --工资下限  
    22.         FUNCTION EXIST_EMP(P_EMPNO NUMBER)  RETURN  BOOLEAN; --判断雇员是否存在函数  
    23.         PROCEDURE SHOW_MESSAGE; --显示信息过程  
    24.         ------------------------------- 初始化过程 ----------------------------  
    25.         PROCEDURE INIT(P_MAX NUMBER,P_MIN NUMBER)    
    26.         IS    
    27.         BEGIN  
    28.          SELECT COUNT(*) INTO V_EMP_COUNT FROM EMP;   
    29. V_MAX_SAL:=P_MAX;   
    30.          V_MIN_SAL:=P_MIN;   
    31.          V_MESSAGE:='初始化过程已经完成!';   
    32.          SHOW_MESSAGE;    
    33.         END INIT;   
    34. ---------------------------- 显示雇员列表过程 ---------------------  
    35.         PROCEDURE LIST_EMP    
    36.          IS    
    37.         BEGIN  
    38. DBMS_OUTPUT.PUT_LINE('姓名       职务      工资');   
    39.         FOR emp_rec IN (SELECT * FROM EMP)   
    40.         LOOP   
    41.     DBMS_OUTPUT.PUT_LINE(RPAD(emp_rec.ename,10,'')||RPAD(emp_rec.job,10,' ')||TO_CHAR(emp_rec.sal));   
    42.          END LOOP;   
    43.          DBMS_OUTPUT.PUT_LINE('雇员总人数'||V_EMP_COUNT);   
    44.         END LIST_EMP;   
    45. ----------------------------- 插入雇员过程 -----------------------------  
    46.         PROCEDUREINSERT_EMP(P_EMPNO     NUMBER,P_ENAMEVARCHAR2,P_JOB    VARCHAR2,P_SAL NUMBER)   
    47.          IS    
    48.         BEGIN  
    49.         IF NOT EXIST_EMP(P_EMPNO) THEN  
    50.         INSERT INTO EMP(EMPNO,ENAME,JOB,SAL)        VALUES(P_EMPNO,P_ENAME,P_JOB,P_SAL);   
    51.         COMMIT;    
    52.         V_EMP_COUNT:=V_EMP_COUNT+1;   
    53.         V_MESSAGE:='雇员'||P_EMPNO||'已插入!';   
    54.         ELSE  
    55. V_MESSAGE:='雇员'||P_EMPNO||'已存在,不能插入!';   
    56.       END IF;   
    57.      SHOW_MESSAGE;    
    58.      EXCEPTION   
    59.     WHEN OTHERS THEN  
    60.      V_MESSAGE:='雇员'||P_EMPNO||'插入失败!';   
    61.      SHOW_MESSAGE;   
    62.      END INSERT_EMP;   
    63. --------------------------- 删除雇员过程 --------------------  
    64.          PROCEDURE DELETE_EMP(P_EMPNO NUMBER)    
    65.         IS    
    66.         BEGIN    
    67.         IF EXIST_EMP(P_EMPNO) THEN  
    68.         DELETE FROM EMP WHERE EMPNO=P_EMPNO;   
    69.         COMMIT;   
    70.          V_EMP_COUNT:=V_EMP_COUNT-1;   
    71.          V_MESSAGE:='雇员'||P_EMPNO||'已删除!';   
    72.          ELSE  
    73. V_MESSAGE:='雇员'||P_EMPNO||'不存在,不能删除!';   
    74.     END IF;   
    75.     SHOW_MESSAGE;   
    76.      EXCEPTION   
    77.      WHEN OTHERS THEN  
    78.      V_MESSAGE:='雇员'||P_EMPNO||'删除失败!';   
    79.      SHOW_MESSAGE;   
    80.     END DELETE_EMP;   
    81. --------------------------------------- 修改雇员工资过程 ------------------------------------  
    82.         PROCEDURE CHANGE_EMP_SAL(P_EMPNO NUMBER,P_SAL NUMBER)    
    83.          IS    
    84.          BEGIN    
    85.          IF (P_SAL>V_MAX_SAL OR P_SAL<V_MIN_SAL) THEN  
    86.          V_MESSAGE:='工资超出修改范围!';   
    87.         ELSIF NOT EXIST_EMP(P_EMPNO) THEN  
    88.         V_MESSAGE:='雇员'||P_EMPNO||'不存在,不能修改工资!';   
    89. ELSE  
    90.          UPDATE EMP SET SAL=P_SAL WHERE EMPNO=P_EMPNO;   
    91.         COMMIT;   
    92.         V_MESSAGE:='雇员'||P_EMPNO||'工资已经修改!';   
    93.         END IF;   
    94.         SHOW_MESSAGE;   
    95.         EXCEPTION   
    96.          WHEN OTHERS THEN  
    97.          V_MESSAGE:='雇员'||P_EMPNO||'工资修改失败!';   
    98.          SHOW_MESSAGE;   
    99.          END CHANGE_EMP_SAL;   
    100. ---------------------------- 显示信息过程 ----------------------------  
    101.          PROCEDURE SHOW_MESSAGE    
    102.         IS    
    103.         BEGIN  
    104.          DBMS_OUTPUT.PUT_LINE('提示信息:'||V_MESSAGE);   
    105.         END SHOW_MESSAGE;   
    106. ------------------------ 判断雇员是否存在函数 -------------------  
    107.          FUNCTION EXIST_EMP(P_EMPNO NUMBER)   
    108.          RETURN BOOLEAN    
    109.          IS  
    110.         V_NUM NUMBER; --局部变量  
    111.         BEGIN  
    112.         SELECT COUNT(*) INTO V_NUM FROM EMP WHERE EMPNO=P_EMPNO;   
    113. IF V_NUM=1 THEN    
    114.            RETURN TRUE;   
    115.          ELSE  
    116.          RETURN FALSE;   
    117.         END IF;    
    118.         END EXIST_EMP;   
    119.         -----------------------------  
    120.         END EMP_PK;  
    1. CREATE OR REPLACE PACKAGE EMP_PK   
    2.         --包头部分   
    3.         IS  
    4.         V_EMP_COUNT NUMBER(5);                
    5.         --雇员人数  
    6.         PROCEDURE INIT(P_MAX NUMBER,P_MIN NUMBER);  --初始化  
    7.         PROCEDURE LIST_EMP;                       
    8.         --显示雇员列表  
    9. PROCEDURE INSERT_EMP(P_EMPNO        NUMBER,P_ENAMEVARCHAR2,P_JOB VARCHAR2,  
    10.         P_SAL NUMBER);                        
    11.         --插入雇员  
    12.         PROCEDURE DELETE_EMP(P_EMPNO NUMBER);       --删除雇员  
    13.          PROCEDURE CHANGE_EMP_SAL(P_EMPNO NUMBER,P_SAL NUMBER);   
    14.         --修改雇员工资  
    15.         END EMP_PK;  
    16.         /CREATE OR REPLACE PACKAGE BODY EMP_PK  
    17.          --包体部分   
    18.         IS  
    19.         V_MESSAGE VARCHAR2(50); --显示信息  
    20. V_MAX_SAL NUMBER(7); --工资上限  
    21.         V_MIN_SAL NUMBER(7); --工资下限  
    22.         FUNCTION EXIST_EMP(P_EMPNO NUMBER)  RETURN  BOOLEAN; --判断雇员是否存在函数  
    23.         PROCEDURE SHOW_MESSAGE; --显示信息过程  
    24.         ------------------------------- 初始化过程 ----------------------------  
    25.         PROCEDURE INIT(P_MAX NUMBER,P_MIN NUMBER)   
    26.         IS   
    27.         BEGIN  
    28.          SELECT COUNT(*) INTO V_EMP_COUNT FROM EMP;  
    29. V_MAX_SAL:=P_MAX;  
    30.          V_MIN_SAL:=P_MIN;  
    31.          V_MESSAGE:='初始化过程已经完成!';  
    32.          SHOW_MESSAGE;   
    33.         END INIT;  
    34. ---------------------------- 显示雇员列表过程 ---------------------  
    35.         PROCEDURE LIST_EMP   
    36.          IS   
    37.         BEGIN  
    38. DBMS_OUTPUT.PUT_LINE('姓名       职务      工资');  
    39.         FOR emp_rec IN (SELECT * FROM EMP)  
    40.         LOOP  
    41.     DBMS_OUTPUT.PUT_LINE(RPAD(emp_rec.ename,10,'')||RPAD(emp_rec.job,10,' ')||TO_CHAR(emp_rec.sal));  
    42.          END LOOP;  
    43.          DBMS_OUTPUT.PUT_LINE('雇员总人数'||V_EMP_COUNT);  
    44.         END LIST_EMP;  
    45. ----------------------------- 插入雇员过程 -----------------------------  
    46.         PROCEDUREINSERT_EMP(P_EMPNO     NUMBER,P_ENAMEVARCHAR2,P_JOB    VARCHAR2,P_SAL NUMBER)  
    47.          IS   
    48.         BEGIN  
    49.         IF NOT EXIST_EMP(P_EMPNO) THEN  
    50.         INSERT INTO EMP(EMPNO,ENAME,JOB,SAL)        VALUES(P_EMPNO,P_ENAME,P_JOB,P_SAL);  
    51.         COMMIT;   
    52.         V_EMP_COUNT:=V_EMP_COUNT+1;  
    53.         V_MESSAGE:='雇员'||P_EMPNO||'已插入!';  
    54.         ELSE  
    55. V_MESSAGE:='雇员'||P_EMPNO||'已存在,不能插入!';  
    56.       END IF;  
    57.      SHOW_MESSAGE;   
    58.      EXCEPTION  
    59.     WHEN OTHERS THEN  
    60.      V_MESSAGE:='雇员'||P_EMPNO||'插入失败!';  
    61.      SHOW_MESSAGE;  
    62.      END INSERT_EMP;  
    63. --------------------------- 删除雇员过程 --------------------  
    64.          PROCEDURE DELETE_EMP(P_EMPNO NUMBER)   
    65.         IS   
    66.         BEGIN   
    67.         IF EXIST_EMP(P_EMPNO) THEN  
    68.         DELETE FROM EMP WHERE EMPNO=P_EMPNO;  
    69.         COMMIT;  
    70.          V_EMP_COUNT:=V_EMP_COUNT-1;  
    71.          V_MESSAGE:='雇员'||P_EMPNO||'已删除!';  
    72.          ELSE  
    73. V_MESSAGE:='雇员'||P_EMPNO||'不存在,不能删除!';  
    74.     END IF;  
    75.     SHOW_MESSAGE;  
    76.      EXCEPTION  
    77.      WHEN OTHERS THEN  
    78.      V_MESSAGE:='雇员'||P_EMPNO||'删除失败!';  
    79.      SHOW_MESSAGE;  
    80.     END DELETE_EMP;  
    81. --------------------------------------- 修改雇员工资过程 ------------------------------------  
    82.         PROCEDURE CHANGE_EMP_SAL(P_EMPNO NUMBER,P_SAL NUMBER)   
    83.          IS   
    84.          BEGIN   
    85.          IF (P_SAL>V_MAX_SAL OR P_SAL<V_MIN_SAL) THEN  
    86.          V_MESSAGE:='工资超出修改范围!';  
    87.         ELSIF NOT EXIST_EMP(P_EMPNO) THEN  
    88.         V_MESSAGE:='雇员'||P_EMPNO||'不存在,不能修改工资!';  
    89. ELSE  
    90.          UPDATE EMP SET SAL=P_SAL WHERE EMPNO=P_EMPNO;  
    91.         COMMIT;  
    92.         V_MESSAGE:='雇员'||P_EMPNO||'工资已经修改!';  
    93.         END IF;  
    94.         SHOW_MESSAGE;  
    95.         EXCEPTION  
    96.          WHEN OTHERS THEN  
    97.          V_MESSAGE:='雇员'||P_EMPNO||'工资修改失败!';  
    98.          SHOW_MESSAGE;  
    99.          END CHANGE_EMP_SAL;  
    100. ---------------------------- 显示信息过程 ----------------------------  
    101.          PROCEDURE SHOW_MESSAGE   
    102.         IS   
    103.         BEGIN  
    104.          DBMS_OUTPUT.PUT_LINE('提示信息:'||V_MESSAGE);  
    105.         END SHOW_MESSAGE;  
    106. ------------------------ 判断雇员是否存在函数 -------------------  
    107.          FUNCTION EXIST_EMP(P_EMPNO NUMBER)  
    108.          RETURN BOOLEAN   
    109.          IS  
    110.         V_NUM NUMBER; --局部变量  
    111.         BEGIN  
    112.         SELECT COUNT(*) INTO V_NUM FROM EMP WHERE EMPNO=P_EMPNO;  
    113. IF V_NUM=1 THEN   
    114.            RETURN TRUE;  
    115.          ELSE  
    116.          RETURN FALSE;  
    117.         END IF;   
    118.         END EXIST_EMP;  
    119.         -----------------------------  
    120.         END EMP_PK;  
    结果为:
    Sql代码 复制代码
    1. 程序包已创建。   
    2.         程序包主体已创建。  
    1. 程序包已创建。  
    2.         程序包主体已创建。  

    步骤2:初始化包:
    Sql代码 复制代码
    1. SET SERVEROUTPUT ON  
    2. EXECUTE EMP_PK.INIT(6000,600);  
    1. SET SERVEROUTPUT ON  
    2. EXECUTE EMP_PK.INIT(6000,600);  

    显示为:
    Sql代码 复制代码
    1. 提示信息:初始化过程已经完成!  
    1. 提示信息:初始化过程已经完成!  

    步骤3:显示雇员列表:
    Sql代码 复制代码
    1. EXECUTE EMP_PK.LIST_EMP;  
    1. EXECUTE EMP_PK.LIST_EMP;  

    显示为:
    Sql代码 复制代码
    1. 姓名          职务          工资   
    2.         SMITH       CLERK       1560   
    3.         ALLEN       SALESMAN    1936   
    4.         WARD        SALESMAN    1830   
    5.         JONES       MANAGER     2975   
    6.         ...   
    7.         雇员总人数:14   
    8.         PL/SQL 过程已成功完成。  
    1. 姓名          职务          工资  
    2.         SMITH       CLERK       1560  
    3.         ALLEN       SALESMAN    1936  
    4.         WARD        SALESMAN    1830  
    5.         JONES       MANAGER     2975  
    6.         ...  
    7.         雇员总人数:14  
    8.         PL/SQL 过程已成功完成。  

    步骤4:插入一个新记录:
    Sql代码 复制代码
    1. EXECUTE EMP_PK.INSERT_EMP(8001,'小王','CLERK',1000);  
    1. EXECUTE EMP_PK.INSERT_EMP(8001,'小王','CLERK',1000);  

    显示结果为:
    Sql代码 复制代码
    1. 提示信息:雇员8001已插入!   
    2. PL/SQL 过程已成功完成。  
    1. 提示信息:雇员8001已插入!  
    2. PL/SQL 过程已成功完成。  

    步骤5:通过全局变量V_EMP_COUNT查看雇员人数:
    Sql代码 复制代码
    1. BEGIN  
    2. DBMS_OUTPUT.PUT_LINE(EMP_PK.V_EMP_COUNT);   
    3. END;  
    1. BEGIN  
    2. DBMS_OUTPUT.PUT_LINE(EMP_PK.V_EMP_COUNT);  
    3. END;  

    显示结果为:
    Sql代码 复制代码
    1. 15   
    2. PL/SQL 过程已成功完成。  
    1. 15  
    2. PL/SQL 过程已成功完成。  

    步骤6:删除新插入记录:
    Sql代码 复制代码
    1. EXECUTE EMP_PK.DELETE_EMP(8001);  
    1. EXECUTE EMP_PK.DELETE_EMP(8001);  

    显示结果为:
    Sql代码 复制代码
    1. 提示信息:雇员8001已删除!   
    2.         PL/SQL 过程已成功完成。  
    1. 提示信息:雇员8001已删除!  
    2.         PL/SQL 过程已成功完成。  

    再次删除该雇员:
    Sql代码 复制代码
    1. EXECUTE EMP_PK.DELETE_EMP(8001);  
    1. EXECUTE EMP_PK.DELETE_EMP(8001);  

    结果为:
    Sql代码 复制代码
    1. 提示信息:雇员8001不存在,不能删除!  
    1. 提示信息:雇员8001不存在,不能删除!  

    步骤7:修改雇员工资:
    Sql代码 复制代码
    1. EXECUTE EMP_PK.CHANGE_EMP_SAL(7788,8000);  
    1. EXECUTE EMP_PK.CHANGE_EMP_SAL(7788,8000);  

    显示结果为:
    Sql代码 复制代码
    1. 提示信息:工资超出修改范围!   
    2.         PL/SQL 过程已成功完成。  
    1. 提示信息:工资超出修改范围!  
    2.         PL/SQL 过程已成功完成。  

    步骤8:授权其他用户调用包:
    如果是另外一个用户要使用该包,必须由包的所有者授权,下面授予STUDEN账户对该包的使用权:
    Sql代码 复制代码
    1. GRANT EXECUTE ON EMP_PK TO STUDENT;  
    [sql]
    展开全文
  • MySQL——创建存储过程和函数

    万次阅读 2018-05-22 09:34:00
    简单地说,存储过程就是一条或多条 SQL 语句的集合,可视为批文件,但是其作用不仅限于批处理。...1. 创建存储过程 语法格式: CREATE PROCEDURE SP_name ( [ proc_parameter ] ) [ characteristi...

        简单地说,存储过程就是一条或多条  SQL  语句的集合,可视为批文件,但是其作用不仅限于批处理。存储程序可以分为存储过程和函数。存储过程要用 CALL  语句来调用,并且只能用输出变量返回值。

    1.   创建存储过程

        语法格式:

        CREATE  PROCEDURE   SP_name  (  [ proc_parameter ] )

            [ characteristics  ...  ]   routine_body 

    【注释】

        a.    CREATE  PROCEDURE:    创建存储过程的关键字。
        b.    sp_name:    存储过程的名字。 

        c.    proc_parameter:为存储过程的参数列表,列表形式如下:

            [  IN  |   out   |   INOUT  ]  param_name  type 

           IN  表示输入参数;OUT  表示输出参数;INOUT  表示即可以输入也可以输出参数;param_name  表示参数名;type  表示参数类型 。
        d.    characteristics  指定存储过程的特性,有以下取值:
    •     LANGUAGE SQL:说明  routine_body 部分是由 SQL语句组成。
    •     [NOT]  DETERMINISTIC:指明存储过程执行的结果是否正确。DETERMINISTIC  表示结果是确定的,每次执行存储过程时,相同的输入会得到相同的输出。 NOT DETERMINISTIC  表示结果是不确定的,相同的输入可能得到不同的输出。如果没有指定值,默认为 NOT DETERMINISTIC。
    •     {CONTAINS SQL |  NO SQL  |  READS SQL DATA  |  MODIFIES SQL DATA }:指明子程序使用SQL语句的限制。CONTAINS SQL表明子程序包含  SQL  语句,但是不包含读写数据的语句; NO SQL 表明子程序不包含SQL 语句;  READS SQL DATA  表明子程序包含读数据的语句;   MODIFIES SQL DATA  表明子程序包含写数据的语句。默认情况下,系统会指定为  CONTAINS SQL。
    •     SQL SECURITY {  DEFINER  |  INVOKER }:指明谁有权限来执行。DEFINER 表示只有定义者才能执行。INVOKER  表示拥有权限的调用者可以执行。默认情况下,系统指定为DEFINER。
    •     COMMENT  ‘string’:注释信息,可以用来描述存储过程或函数。

    e.    routine body是SQL代码的内容,可以用BEGIN..END来表示SQL代码的开始和结束。


    【例】创建查看  fruits 表的存储过程。SQL 语句如下:

    mysql> DELIMITER  //
    mysql> CREATE  PROCEDURE  proc()
        -> BEGIN
        -> SELECT  *  FROM  fruits;
        -> END  //
    Query OK, 0 rows affected (0.35 sec)
    mysql> DELIMITER ;

        这个存储过程和使用  SELECT  语句查看表得到的结果是一样的, 当然存储过程也可以是很多语句的复杂组合,其本身也可以调用其他的函数,来组成更加复杂的操作。

        【注】    "DELIMITER   //”语句的作用是将  MySQL  的结束符设置为 // ,因为  MySQL 默认的语句结束符号为分号(;),为了避免与存储过程中的  SQL 语句结束符冲突,需要使用  DELIMITER  改变存储过程的结束符,并以“END  //”结束存储过程,存储过程,定义完毕之后再使用  DELIMITER  恢复默认结束符。DELIMITER 也可以指定其他符号作为结束符。


    【例】 创建名为 countproc  的存储过程,用于获取  fruits 表中的记录数。代码如下:

    mysql> DELIMITER  //
    mysql> CREATE  PROCEDURE  countproc  (  OUT  paraml  INT )
        -> BEGIN
        -> SELECT  COUNT(*)  INTO  paraml  FROM  fruits;
        -> END  //
    Query OK, 0 rows affected (0.07 sec)
    
    mysql> DELIMITER  ;

    2.   创建存储函数

        语法格式:

         CREATE  FUNCTION   func_name  (  [ func_parameter ] )

                 RETURNS  type   

         [ characteristics  ...  ]   routine_body 

    •     CREATE  FUNCTION  为创建存储函数的关键字;
    •     func_name  表示存储函数的名称;
    •     func_parameter  为存储函数的参数列表,参数列表的形式如下:
                [  IN   |    OUT   |   INOUT ]  param_name   type

          其中,IN 表示输入参数;  OUT 表示输出参数; INOUT  表示既可以输入也可以输出参数;  param_name 表示参数名称; type 表示参数的类型,该类型可以是  MySQL 数据库中的任意类型。

    •     RETURNS type  语句表示函数返同数据的类型;
    •     characteristic  指定存储函数的特性,取值与创建存储过程时相同。


    【例】 创建存储函数,名称为  namebyzip, 该函数返回  SELECT  语句的查询结果,数值类型为字符串型。代码如下:

    mysql> DELIMITER  //
    mysql> CREATE  FUNCTION  namebyzip()
        -> RETURNS  CHAR(50)
        -> RETURN  (  SELECT  s_name  FROM  suppliers  WHERE  s_call='48075');
        -> //
    Query OK, 0 rows affected (0.11 sec)
    
    mysql> DELIMITER  ;

    3.   变量的使用

        变量可以在子程序中声明并使用,这些变量的作用范围是在  BEGIN  ...  END 程序中。

       a.   定义变量

        语法格式:

        DECLARE  var_namel [, var_name] ...  date_type  [  DEFAULT  value ];

    • var_name  为局部变量的名称。
    • DEFAULT  value  子句给变最提供一个默认值,这个值除了可以声明为一个常数之外,还可以指定为一个表达式。如果没有DEFAULT  子句,初始值为NULL。

        【例】定义名称为  myparam  的变量,类型为  INT,默认值为100。代码如下:

     DECLARE  myparam  INT  DEFAULT  100;

        b.   为变量赋值

        变量定义之后,为变量赋值可以改变量的默认值,MysSQL中使用 SET 语句为变量赋值,语法格式如下:

        SET var_name = expr [ , var_name = expr ]   ...  ;


        【例】声明3个变量,分别为  varl、var2 和 var3, 数据类型为  INT,使用  SET  为变量赋值。代码如下:

    DECLARE var1, var2, var3 INT;
    SET var1 = 10, var2 = 20;
    SET var3 = var1 + var2;

      

        MySQL  中还可以通过  SELECT   ...  INTO  为一个或多个变量赋值, 语法如下:

        SELECT   col_name  [  ,  ...   ]   INTO Var_name  [  ,  ...   ]   table_expr;

    • col_name  表示字段名称;
    • var_name  表示定义的变量名称;
    • table_expr  表示查询条件表达式,包括表名称和 WHERE 子句。

    【例】声明变量 fruit_name  和  fruitprice  通过 SELECT ... INTO 语句查询指定记录并为变量赋值。  代码如下:

    DECLARE    fruitname  CHAR(50);
    
    DECLARE    fruitprice   DECIMAL(8,2);
    
    SELECT  f_name,f_price  INTO  fruitname,  fruitprice
    
    FROM  fruits  WHERE  f_id ='a1';
    
    

    4.   定义条件和处理程序

        定义条件是事先定义程序执行过程中遇到的问题,处理程序定义了在遇到这些问题时应当采取的处理方式,并且保证存储过程或函数在遇到警告或错误时能继续执行。这样可以增强存储程序处理问题的能力,避免程序异常停止运行。

        a.    定义条件

         DECLARE condition_name CONDITION FOR  [condition_type] 
       [condition_type]:
            SQLSTATE [VALUE] sqlstate_value  |  mysql_error_code


    •     condition name  参数表示条件的名称;
    •     condition_type  参数表示条件的类型;
    •     sqlstate_value 和  mysql_error_code  都可以表示  MySQL 中的错误,sqlstate_value为长度为 5 的字符串类型错误代码,mysql_error_code 为数值类型错误代码。例如,ERROR 1142(42000)中,sqlstate_value 的值是42000,mysql_ error_code的值是  1142。
        这个语句用于指定需要特殊处理的条件,可以将一个名字和指定的错误条件关联起来。这个名字可以随后被用在定义处理程序的  DECLARE  HANDLER 语句中。


    【例】定义  ERROR 1148(42000)  错误, 名称为  command_not_allowed ,  用两种不同的方法来定义。代码如下:

      //方法一:  使用  sqlstate_value
      DECLARE command_not_allowed   CONDITION  FOR   SQLSTATE  '42000';
    
     //方法二:  使用mysql_error_code
      DECLARE  command_not_allowed CONDITION FOR 1148

        b.  定义处理程序

        语法格式如下:

        DECLARE   handler_type   HANDLER FOR   condition_value  [  ,...  ]    sp_statement
        handler_type:
      CONTINUE   |   EXIT  |  UNDO

        condition_value:
      SQLSTATE   [  VALUE  ] sqlstate_value
        |condition_name
        |SQLWARNING
        |NOT FOUND
        |SQLEXCEPTION
        |mysql_error_code

    【注释】

        (1)  hander_type  为错误处理方式,参数取3个值:  CONTINUE、 EXIT  和  UNDO.   CONTINUE  表示遇到错误不处理,继续执行; EXIT  表示遇到错误马上退出; UNDO  表示遇到错误后撒回之前的操作,MySOL中暂时不支持这样的操作。
        (2)   condition_value  表示错误类型,可以有以下取值:

    •     SQLSTATE  [VALUE]  sqlstate_value  表示包含5个字符的字符串错误值。
    •     condition_name  表示  DECLARE CONDITION  定义的错误条件名称。
    •     SQLWARNING  匹配所有以  01 开头的  SQLSTATE  错误代码。
    •     NOT FOUND  匹配所有以  02  开头的  SQLSTATE  错误代码。
    •     SQLEXCEPTION  匹配所有未被  SQLWARNING  或  NOT FOUND 捕获的  SQLSTATE  错误代码。
      (3) mysql_error_code 匹配数值类型错误代码。
      (4) sp_statement  参数为程序语句段,表示在遇到定义的错误时,需要执行的存储过程或函数。


    【例】定义处理程序的几种方式。代码如下:

    //方法一:捕获sqlstate_value
      DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='NO_SUCH_TABLE';
    

        第一种方法是捕获  sqlstate_value   值。如果遇到  sqlstate_value 值为 42S02, 执行  CONTINUE  操作,并且输出  NO_ SUCH_TABLE  信息。

     //方法二:  捕获  mysql_error_code
      DECLARE CONTINUE HANDLER FOR 1146 SET   @info= 'NO_SUCH_TABLE' ;

        第二种方法是捕获  mysql_error_code值。如果遇到  mysql_error_code值为  1146, 执行  CONTINUE  操作,并且输出NO_ SUCH_TABLE  信息。

     //方法三:  先定义条件,然后调用
      DECLARE  no_such_table CONDITION FOR 1146;
      DECLARE   CONTINUE   HANDLER   FOR  NO_SUCH_TABLE   SET @info= 'NO_SUCH_TABLE' ;

        第三种方法是先定义条件,然后再调用条件。这里先定义  no_such_table  条件,遇到 1146  错误就执行  CONTINUE  操作。

     //方法四:  使用  SQLWARNING
      DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';
    

        第四种方法是使用  SQLWARNING。SQLWARNING  捕获所有以  01 开头的  sqlstate_value  然后执行  EXIT  操作,并且输出  ERROR  信息。

      //方法五:  使用 NOT FOUND
       DECLARE   EXIT   HANDLER  FOR   NOT  FOUND  SET @info= 'NO_SUCH_TABLE' ;

        第五种方法是使用  NOT FOUND。NOT FOUND  捕获所有以  02 开头的  sqlstate_value  值然后执行  EXIT  操作,并且输出NO_SUCH_TABLE 信息。

     //方法六:  使用 SOLEXCEPTION
      DECLARE  EXIT HANDLER   FOR   SQLEXCEPTON SET @infom='ERROR';
        第六种方法是使用  SQLEXCEPTION。SQLEXCEPTION  捕获所有未被  SQLWARNING  或  NOT FOUND 捕获的  sqlstate_ value值, 然后执行  EXIT 操作,并且输出  ERROR  信息。

      

    【例】定义条件和处理程序。

    mysql> CREATE TABLE t(s1 int,primary key(s1));
    Query OK, 0 rows affected
    
    mysql> DELIMITER //
    mysql> CREATE PROCEDURE handlerdemo()
        -> BEGIN
        -> DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2=1;
        -> SET @x=1;
        -> INSERT INTO t VALUES(1);
        -> SET @x=2;
        -> INSERT INTO t VALUES(1);
        -> SET @x=3;
        -> END;
        -> //
    Query OK, 0 rows affected
    
    mysql> DELIMITER ;
    mysql> CALL handlerdemo();
    Query OK, 0 rows affected
    
    mysql> SELECT @x;
    +----+
    | @x |
    +----+
    |  3 |
    +----+
    1 row in set


    5.   光标的使用

        查询语句可能返回多条记录,如果数据量非常大,需要在存储过程和存储函数中使用光标来逐条读取查询结果集中的记录。

        光标必须在声明处理程序之前被声明,并且变量和条件还必须在声明光标或处理程序之前被声明。 

        (1)   声明光标

        语法格式:

        DECLARE   cursor_name   CURSOR   FOR   selec_statement

    •     cursor_name  参数表示光标的名称;
    •      select_statement  参数表示  SELECT  语句的内容,返回一个用于创建光标的结果集。

       【例】 声明名称为  cursor_fruit 的光标。代码如下:

    DECLARE cursor_fruits CURSOR FOR SELECT f_name,f_price FROM fruits;
          光标的名称为 cursor_fruit,  SELECT  语句部分从 fruits  表中查询出  f_name  和  f_price 字段的值。


     (2)   打开光标

        语法格式:

        OPEN cursor_name

    【例】打开名为  cursor_ fruit  的光标。代码如下:

    OPEN cursor_fruits;

        (3)   使用光标

        语法格式:

        FETCH   cursor_name   INTO   var_name  [  , var_name  ]  ...  {参数名称}

    •     cursor_name  参数表示光标的名称;
    •     var_ name  参数表示将光标中的  SELECT  语句查询出来的信息存入该参数中,var_name  必须在声明光标之前就定义好。

        【例】 使用名为   cursor_fruit  的光标查询,并将查询出来的数据存入  fruit_name 和  fruit_price  两个变量中。

    代码如下:

    FETCH cursor_fruits INTO fruits_name,fruits_price;

        上面的示例中,将光标  cursor_fruit  中  SELECT  语句在询出来的信息存入  fruit_name 和  fruit_price   中。fruit_name 和  fruit_price  必须在前面已经定义。

        (4)   关闭光标

        语法格式:

        CLOSE cursor_name{光标名称}

         如果光标未被明确地关闭,就会在声明的复合语句的未尾被关闭 。 

        【例】关闭名为  cursor_fruit  的光标。代码如下:

      CLOSE cursor_fruit;

    【注】 MySQL中光标只能在存储过程和函数中使用。


    存储过程与自定义函数的区别

    • 存储过程实现的功能要复杂一些;而函数的针对性更强
    • 存储过程可以返回多个值;函数只能有一个返回值
    • 存储过程一般独立的来执行;而函数可以作为其他SQL语句的组成部分来出现。


    【注】参考于清华大学出版社《MySQL数据库应用案例课堂》2016年1月第1版

    展开全文
  • 一、C#创建存储过程并调用

    千次阅读 热门讨论 2018-10-31 18:23:55
    一、存储过程 1、表的结构 在这里插入代码片 2、无参数存储过程 create procedure GetStuCou as begin select * from Student s left join Course c on s.C_S_Id=c.C_Id end ...
  • 系统存储过程是系统创建存储过程,目的在于能够方便的从系统表中查询信息或完成与更新数据库表相关的管理任务或其他的系统管理任务。系统存储过程主要存储在master数据库中,以“sp”下划线开头的存储过程。尽管...
  • 创建存储过程(CREATE PROCEDURE) 基本语法格式如下: CREATE PROCEDURE sp_name (parameters) [characteristics ...] routine_body 其中:CREATE PROCEDURE为创建存储过程的关键字;sp_name为存储过程的名称...
  • 存储过程五种使用场景比较

    千次阅读 2018-01-19 01:40:56
    存储过程五种使用场景比较 1. 使用 JDBC API 直接调用存储过程 Java Database Connectivity (JDBC) API 是 J2EE 的一部分,是 Java 语言访问关系数据库的基于标准的首要机制,提供了对数据库访问和缓存管理的直接...
  • Oracle存储过程

    万次阅读 多人点赞 2019-07-01 14:52:17
    1.创建Oracle存储过程 prodedure create or replace procedure test(var_name_1 in type,var_name_2 out ty pe) as --声明变量(变量名 变量类型) begin --存储过程的执行体 end test; 打印出输入的时间信息 create...
  • 一、创建创建存储过程使用CREATE PROCEDURE语句,语法格式如下:CREATE PROCEDURE proc_name ([proc_parameter]) [characteristics...] body(1)CREATE PROCEDURE:创建存储过程关键字(2)proc_name:存储过程...
  • 这些变量是存储过程的本地变量,但是我们得注意,变量必须先声明才能使用它。而我们如果要在存储过程中声明一个变量,可以使用DECLARE语句,来看下sql语法:DECLARE variable_name datatype(size) DEFAULT ...
  • DB2数据库使用存储过程详解

    万次阅读 2018-08-02 09:52:46
    存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL语句集,经编译存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。  主要特点: 类...
  • MySQL存储过程使用

    千次阅读 2014-09-30 01:44:40
    MySQL存储过程, Procedure
  • sqlserver 存储过程使用

    万次阅读 2019-12-29 22:12:58
    存储过程执行一次,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句。这样就可以提高存储过程的性能。 Ø 存储过程的概念 存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译存储在...
  • 数据库存储过程简单介绍

    千次阅读 2019-03-05 15:37:35
    存储过程 存储过程就是一条或多...创建存储过程 创建存储过程的基本语法 CREATE PROCEDURE 存储过程名称([存储过程的参数列表]) [存储过程的特性]routine_body 存储过程的参数列表语法如下 ([[IN|OUT|INOUT]参数名...
  • Mysql 命令行下建立存储过程

    千次阅读 2019-06-26 02:55:32
    建立存储过程的sql如下: CREATEPROCEDUREproc_variable() BEGIN DECLAREdec_var_VARCHAR(100); DECLARErep_numINT; DECLAREdec_varCURSORforSELECTID_FROMACT_RU_VARIABLEWHEREN...
  • sql2005创建存储过程(需要注意的几点)创建存储过程。存储过程是已保存的 Transact-SQL 语句集合,或对 Microsoft .NET Framework 公共语言运行时 (CLR) 方法的引用,可接收并返回用户提供的参数。可以创建过程供...
  • (2)CONCAT_WS()//使用指定的分隔符进行字符连接 (3)FORMAT()//数字格式化 (4)LOWER()//转化小写 (5)UPPER()//转换大写 (6)LEFT()//获取左侧字符 (7)RIGHT()//获取右侧字符 (8)LENGTH()//取得字符串...
  • Mysql创建存储过程及遍历查询结果

    万次阅读 2011-05-16 14:46:00
    Mysql创建存储过程及遍历查询结果
  • 为何要这么使用呢? 1、可以防止项目在开发时误删程序运行必备数据, 2、特方便,简洁(只需要把写好的数据库脚本写成文件放入工程目录下,在你的yml,或properties文件里写上一点配置就好)! 在开发中有这两点理由我...
  • 这篇文章主要介绍了oracle 创建,删除存储过程,参数传递,创建,删除存储函数,存储过程和函数的查看,包,系统包等相关资料,需要的朋友可以参考下 oracle 创建,删除存储过程,参数传递,创建,删除存储函数,存储过程和函数...
  • SQL 实验项目6_存储过程

    千次阅读 2019-12-03 00:21:19
    5.创建存储过程sg,根据输入的学号和课程号,获得指定学号和课程号的课程成绩。 *6.创建存储过程update_s_1,修改指定学号的数据信息。 五、实验结果(包括设计效果、测试数据、运行结果等) 1.创建存储过程s_...
  • Mysql存储过程使用临时表

    千次阅读 2013-10-23 17:48:39
    临时表:只有在当前连接情况下, TEMPORARY 表才是可见的。当连接关闭时, TEMPORARY 表被自动取消。这意味着两个不同的连接可以使用... TEMPORARY TABLES 权限,才能创建临时表。可以通过指定 ENGINE|TYPE = M
  • 数据库事务&存储过程

    千次阅读 2019-02-28 15:58:24
    一是本地临时存储过程,以井字号(#)作为其名称的第一个字符,则该存储过程将成为一个存放在tempdb数据库中的本地临时存储过程,且只有创建它的用户才能执行它; 二是全局临时存储过程,以两个井字号(##)号开始,则...
  • 调用执行有出参的存储过程

    千次阅读 2017-10-16 11:20:17
    oracle 存储过程篇-有出参如何调用  http://www.cnblogs.com/gaojun/archive/2012/12/21/2827494.html DECLARE v_nanme varchar2(500); v_age varchar2(500); BEGIN proc_ec_getcomplete('241753593',v...
  • mysql存储过程的权限 definer

    千次阅读 2018-03-13 14:08:56
    CREATE ROUTINE 创建存储过程 EXECUTE运行存储过程 存储过程的创建者拥有存储过程的ALTER、CREATE、EXECUTE权限。 DEFINER用于指明存储过程是由哪个用户定义的,默认存储过程的定义者是存储过程,跟存储过程的...
  • C#二十六 使用Ado.Net调用存储过程

    千次阅读 2016-05-07 19:05:41
    存储过程是连接式访问数据库的一种延伸,主要是通过命令对象调用数据库系统中的存储过程来完成的。...使用Ado.Net中的SqlCommand可以调用并执行Sql Server数据库的存储过程。 视频课堂https://edu.csdn.net...
  • MySQL---存储过程详解

    千次阅读 多人点赞 2021-03-16 11:03:41
    存储过程简单来说,就是为以后的使用而保存的一条或多条 MySQL 语句的集合。可将其视为批处理文件。虽然他们的作用不仅限于批处理。 存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。 存储过程的...
  • SQL 存储过程 procedure 讲解+代码实例

    千次阅读 多人点赞 2020-04-09 20:34:02
    文章目录1. 存储过程和函数在实际项目中的使用2. 存储过程与函数的比较2.1.... 创建存储过程 create procedure3.3. 调用存储过程 call3.4. 查看存储过程的定义3.5. 修改存储过程 alter procedure...
  • SQL存储过程的优缺点

    千次阅读 2018-07-28 17:17:22
    概要: ...存储过程是可编程的函数,在数据库中创建并保存,可以由SQL语句和控制结构组成。当想要在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 445,021
精华内容 178,008
关键字:

创建存储过程后怎么才能使用