zoukankan      html  css  js  c++  java
  • oracle 开发 第12章 PL/SQL编程

    2016-04-18

    目录

    一、程序块(BLOCK)
      1.DECLARE块
      2.BEGIN块
      3.EXCEPTION块
    二、数据类型(DATA TYPE)
      1.数值类型
      2.字符类型
      3.日期类型
      4.布尔类型

    特殊数据类型(重点!)
      1.%TYPE类型
      2.RECORD类型
      3.%ROWTYPE类型
    三、流程控制
      (1)IF 选择
        1.IF ... THEN ... END IF
        2.IF ... THEN ...ELSE ... END IF
        3.IF ... THEN ... ELSIF ...ELSE ... END IF
      (2) CASE 选择
        CASE ... WHEN ... THEN ... ELSE .. END CASE
      (3)LOOP 循环
        4.LOOP ...EXIT ... END LOOP
        5.LOOP ...EXIT WHEN ... END LOOP
        6.LOOP...CONTINUE...EXIT WHEN...END LOOP
        7.LOOP...CONTINUE WHEN...EXIT WHEN...END LOOP
      (4)WHILE 循环
        8.WHILE...LOOP...END LOOP
      (5)FOR 循环
        9.FOR ... IN... LOOP ...END LOOP
        10.FOR ... IN REVERSE ... LOOP ...END LOOP

    四、游标(CURSOR)
      (1)游标的概念
      (2)游标的使用
      (3)游标的属性
      (4)游标的类型
        1.显式游标
        2.隐式游标
        3.REF游标/引用游标/动态游标
    五、异常(EXCEPTION)
    六、存储过程(PROCEDURE)
      1.无参存储过程
      2.带IN参数的存储过程
      3.带OUT参数的存储过程
      4.带IN OUT 参数的存储过程
      5.带IN参数默认值的存储过程
      查看过程
      删除过程


    一、程序块(BLOCK)
    PL/SQL程序都是以块(BLOCK)为基本单位,PL/SQL块由3部分组成:DECLARE块、BEGIN块、EXCEPTION块。
    1.DECLARE块
    声明部分,声明PL/SQL程序块中用到的变量、常量、游标,DECLARE块是可选的。
    2.BEGIN块
    执行部分,是PL/SQL块的主体,可以执行选择、循环逻辑、多个PL/SQL语句、SQL语句。以BEGIN关键词开始,如果PL/SQL块中代码在运行时出现异常,则执行EXCEPTION块;如果没有异常,则以关键词END结束。
    3.EXCEPTION块
    异常用于处理PL/SQL块中出现的运行时错误。

    --根据给出矩形面积和高度计算其宽度
    DECLARE
    v_width INTEGER;
    v_height INTEGER := 2;
    v_area INTEGER := 6;
    BEGIN
    v_width := v_area / v_height;
    dbms_output.put_line('v_width = '|| v_width);
    EXCEPTION
    WHEN ZERO_DIVIDE THEN
    dbms_output.put_line('Division by zero');
    END;

    二、数据类型(DATA TYPE)
    变量
    变量是指其值在程序运行过程中,可以改变的,数据存储结构。定义变量包括变量名、数据类型。
    例:
    var_countryname VARCHAR2(50) := '中国';

    常量
    常量是指其值在程序运行过程中不可改变的数据存储结构。定义常量包括常量名、数据类型、常量值、CONSTANT关键字。
    例:
    con_day CONSTANT INTEGER := 365;

    数据类型
    数据类型本质上是一种用于描述数据存储的内存结构,用来决定变量中存储数据的类型。
    变量本质上是一种用名称进行识别的标识符号,可以存储不同类型的数据。

    基本数据类型
    1.数值类型
    NUMBER(P,S)、DEC、DECIMAL、DOUBLE、INTEGER、INT、NUMERIC、SMALLINT 整型、浮点型
    PLS_INTEGER、BINARY_INTEGER 整型
    例:
    v_product_id INTEGER;
    v_product_type_id INTEGER;
    v_price NUMBER(5,2);

    2.字符类型
    VARCHAR2 可变长度字符串类型
    CHAR 固定长度字符串类型
    LONG 可变长度字符串类型,最长2GB
    NCHAR、NVARCHAR2 长度由各国字符集确定
    例:
    v_name VARCHAR2(30);
    v_description VARCHAR2(50);

    3.日期类型
    DATE 世纪、年、月、日、时、分、秒

    4.布尔类型
    BOOLEAN 变量值可以为TRUE、FALSE、NULL

    特殊数据类型(重点!)
    1.%TYPE类型
    声明与表中指定列,名称相同的数据类型。
    例:
    v_product_price products.price%TYPE;

    2.RECORD类型
    存储由多个列值组成的一行数据。记录是一种结构化数据类型,用type语句定义。
    例:

    DECLARE
    TYPE emp_type IS RECORD
    (
    var_name varchar2(20),
    var_job varchar2(20),
    var_sal number
    );
    empinfo    emp_type;
    BEGIN
    SELECT ename,job,sal
    INTO empinfo
    FROM emp
    WHERE empno=7369;
    dbms_output.put_line('雇员'||empinfo.var_ename||'的职务是'||empinfo.var_job||'、工资是'||empinfo.var_sal);
    END;

    3.%ROWTYPE类型
    声明与表中所有列,名称相同的数据类型,存储从数据表中检索到的一行数据。
    例:

    DECLARE
    rowvar_emp    emp%ROWTYPE;
    BEGIN
    SELECT *
    INTO rowvar_emp
    FROM emp
    WHERE empno = 7369;
    dbms_output.put_line('雇员'||rowvar_emp.ename||'的编号是'||rowvar_emp.empno||',职务是'||rowvar_emp.job);
    END;

    三、流程控制
    (1)IF 选择
    1.IF ... THEN ... END IF

    DECLARE
    v_count INT := 10;
    v_message VARCHAR2(255);
    BEGIN
    IF v_count > 0 THEN
    v_message := 'v_count is positive';
    dbms_output.put_line(v_message);
    END IF;
    END;

    2.IF ... THEN ...ELSE ... END IF

    DECLARE
    v_count INT := -10;
    v_message VARCHAR2(255);
    BEGIN
    IF v_count > 0 THEN
    v_message := 'v_count is positive';
    ELSE
    v_message := 'v_count is not positive';
    END IF;
    dbms_output.put_line(v_message);
    END;

    3.IF ... THEN ... ELSIF ...ELSE ... END IF

    DECLARE
    v_count INT := -10;
    v_message VARCHAR2(255);
    BEGIN
    IF v_count > 0 THEN
    v_message := 'v_count is positive';
    ELSIF v_count = 0 THEN
    v_message := 'v_count is zero';
    ELSE
    v_message := 'v_count is negative';
    END IF;
    dbms_output.put_line(v_message);
    END;
    --季节判断
    DECLARE
    month INT := 10;
    BEGIN
    IF month >= 0 AND month <= 3 THEN
    dbms_output.put_line('这是春季');
    ELSIF month >= 4 AND month <= 6 THEN
    dbms_output.put_line('这是夏季');
    ELSIF month >= 7 AND month <= 9 THEN
    dbms_output.put_line('这是秋季');
    ELSIF month >= 10 AND month <= 12 THEN
    dbms_output.put_line('这是冬季');
    ELSE
    dbms_output.put_line('对不起,月份不合法!');
    END IF;
    END;

    (2) CASE 选择

    DECLARE
    season INT := 3;
    aboutinfo VARCHAR2(50);
    BEGIN
    CASE season
    WHEN 1 THEN
    aboutinfo := season || '季节包括1、2、3月份';
    WHEN 2 THEN
    aboutinfo := season || '季节包括4、5、6月份';
    WHEN 3 THEN
    aboutinfo := season || '季节包括7、8、9月份';
    WHEN 4 THEN
    aboutinfo := season || '季节包括10、11、12月份';
    ELSE
    aboutinfo := season || '季节不合法';
    END CASE;
    dbms_output.put_line(aboutinfo);
    END;

    (3)LOOP 循环
    4.LOOP ...EXIT ... END LOOP

    DECLARE
    v_counter INT;
    BEGIN
    v_counter := 0;
    LOOP
    v_counter := v_counter + 1;
    dbms_output.put_line('v_counter = ' || v_counter);
    EXIT;
    END LOOP;
    END;

    5.LOOP ...EXIT WHEN ... END LOOP

    DECLARE
    v_counter INT;
    BEGIN
    v_counter := 0;
    LOOP
    v_counter := v_counter + 1;
    dbms_output.put_line('v_counter = ' || v_counter);
    EXIT WHEN v_counter = 5;
    END LOOP;
    END;

    6.LOOP...CONTINUE...EXIT WHEN...END LOOP

    DECLARE
    v_counter INT;
    BEGIN
    v_counter := 0;
    LOOP
    v_counter := v_counter + 1;
    dbms_output.put_line('v_counter = ' || v_counter);
    IF v_counter = 3 THEN
    CONTINUE;
    END IF;
    EXIT WHEN v_counter = 5;
    END LOOP;
    END;

    7.LOOP...CONTINUE WHEN...EXIT WHEN...END LOOP

    DECLARE
    v_counter INT;
    BEGIN
    v_counter := 0;
    LOOP
    v_counter := v_counter + 1;
    dbms_output.put_line('v_counter = ' || v_counter);
    CONTINUE WHEN v_counter = 3;
    EXIT WHEN v_counter = 5;
    END LOOP;
    END;

    (4)WHILE 循环
    8.WHILE...LOOP...END LOOP

    DECLARE
    v_counter INT;
    BEGIN
    v_counter := 0;
    WHILE v_counter < 6 LOOP
    v_counter := v_counter + 1;
    dbms_output.put_line('v_counter = ' || v_counter);
    END LOOP;
    END;

    (5)FOR 循环
    9.FOR ... IN... LOOP ...END LOOP

    DECLARE
    v_counter INT;
    BEGIN
    FOR v_counter IN 1 .. 5 LOOP
    dbms_output.put_line('v_counter = ' || v_counter);
    END LOOP;
    END;

    10.FOR ... IN REVERSE ... LOOP ...END LOOP

    DECLARE
    v_counter INT;
    BEGIN
    FOR v_counter IN REVERSE 1 .. 5 LOOP
    dbms_output.put_line('v_counter = ' || v_counter);
    END LOOP;
    END;

    四、游标(CURSOR)
    (1)游标的概念:
    游标是内存中的一块区域,用于存放SELECT的结果集。在通过查询将行检索到游标中后,PL/SQL程序可以一次从游标中取出一行。游标提供了在结果集中一次一行或者多行的,前进或向后浏览数据的能力。可以把游标当作一个指针,它可以指定结果集中的任何位置,然后允许用户对指定位置的数据进行处理。

    (2)游标的使用:
    1.声明变量,用于存储一行的列值。
    2.声明游标,用于存储SELECT的结果集。主要包括游标名称、为游标提供结果集的SELECT语句。
    3.打开游标,游标在声明之后,必须打开才能使用。
    4.读取游标,一次从游标中获取一行,逐行将结果集中的数据保存到变量中,可以对这些变量执行某些操作。
    5.关闭游标,游标使用完后,必须关闭,以释放系统资源。

    (3)游标的属性:
    无论显示游标、隐式游标,都具有%FOUND、%NOTFOUND、%ISOPEN、%ROWCOUNT 4个属性。
    通过这4个属性,可以获知SQL语句的执行结果,以及该游标的状态信息。
    4个属性 %ROWCOUNT INTEGER 影响到的记录行数
    %FOUND BOOLEAN 影响到了记录 true
    %NOTFOUND BOOLEAN 没有影响到记录 true
    %ISOPEN BOOLEAN 游标打开 true

    (4)游标的类型:
    1.显式游标
    显式游标是由用户声明和操作的游标,用于处理返回多行的查询。使用步骤包括声明游标、打开游标、读取游标、关闭游标。因为游标每次只能读取一行数据,所以对于多条记录,需要反复读取,直到游标读取不到数据为止。
    例1:使用LOOP循环,FETCH..INTO读取显式游标

    DECLARE
    --声明变量
    v_product_id products.product_id%TYPE;
    v_name products.name%TYPE;
    v_price products.price%TYPE;
    --声明游标
    CURSOR v_product_cursor IS
    SELECT product_id, name, price FROM products ORDER BY product_id;
    BEGIN
    --打开游标
    OPEN v_product_cursor;
    --读取游标
    LOOP
    FETCH v_product_cursor
    INTO v_product_id, v_name, v_price;
    EXIT WHEN v_product_cursor%NOTFOUND;
    dbms_output.put_line('v_product_id = ' || v_product_id || ',v_name = ' ||
    v_name || ',v_price = ' || v_price);
    END LOOP;
    --关闭游标
    CLOSE v_product_cursor;
    END;

    例2:使用FOR循环,读取显式游标
    在使用FOR循环遍历游标中的行时,不需要显示的打开、关闭游标,FOR循环会自动执行这些操作。
    例:

    DECLARE
    --声明游标
    CURSOR v_product_cursor IS
    SELECT product_id, name, price FROM products ORDER BY product_id;
    BEGIN
    --读取游标
    FOR v_product IN v_product_cursor LOOP
    dbms_output.put_line('v_product_id = ' || v_product.product_id ||
    ',v_name = ' || v_product.name || ',v_price = ' ||
    v_product.price);
    END LOOP;
    END;

    2.隐式游标
    在PL/SQL程序中执行DML SQL语句时,oracle自动创建隐式游标,名字固定叫sql。单条sql语句所产生的结果集合,用关键字SQL表示隐式游标。多条sql语句,隐式游标SQL永远指的是最后一条sql语句的结果,主要使用在update 和 delete语句。
    例3:使用SQL关键字,读取隐式游标

    BEGIN
    UPDATE scott.emp SET sal = sal * (1 + 0.2) WHERE job = 'SALESMAN';
    --隐式游标
    IF SQL%NOTFOUND THEN
    dbms_output.put_line('没有雇员需要上调工资');
    ELSE
    dbms_output.put_line('' || SQL%ROWCOUNT || '个雇员工资上调20%');
    END IF;
    END;

    3.REF游标/引用游标/动态游标
    REF 游标
    用于处理运行时才能确定的动态SQL查询结果。使用OPEN-FOR循环遍历REF游标中的行,可以将游标分配给不同的查询。
    约束游标(constrained cursor)
    有具体的返回类型,返回类型与REF游标运行的查询中的列相匹配。
    无约束游标(unconstrained cursor)
    没有返回类型,可以运行任何查询。

    例4:使用OPEN-FOR循环,读取REF约束游标

    DECLARE
    --声明REF约束游标类型
    TYPE t_product_cursor IS REF CURSOR RETURN products%ROWTYPE;
    --声明游标
    v_product_cursor t_product_cursor;
    --声明变量,用来存储products表的各列
    v_product products%ROWTYPE;
    BEGIN
    --打开游标
    OPEN v_product_cursor FOR
    SELECT * FROM products WHERE product_id < 5;
    --读取游标
    LOOP
    FETCH v_product_cursor
    INTO v_product;
    EXIT WHEN v_product_cursor%NOTFOUND;
    dbms_output.put_line('product_id = ' || v_product.product_id ||
    ', name = ' || v_product.name || ', price = ' ||
    v_product.price);
    END LOOP;
    --关闭游标
    CLOSE v_product_cursor;
    END;

    例5:使用OPEN-FOR循环,读取REF无约束游标。

    DECLARE
    --声明REF无约束游标类型
    TYPE t_cursor IS REF CURSOR;
    --声明REF游标
    v_cursor t_cursor;
    --声明变量,用来存储products表的各列
    v_product products%ROWTYPE;
    --声明变量,用来存储customers表的各列 
    v_customer customers%ROWTYPE;
    BEGIN
    --打开游标,将来自products表的SELECT结果集,取值到内存的v_cursor游标中
    OPEN v_cursor FOR
    SELECT * FROM products WHERE product_id < 5;
    --读取游标,将内存中的v_cursor游标,取值到v_product变量中
    LOOP
    FETCH v_cursor
    INTO v_product;
    EXIT WHEN v_cursor%NOTFOUND;
    dbms_output.put_line('product_id = ' || v_product.product_id ||
    ', name = ' || v_product.name || ', price = ' ||
    v_product.price);
    END LOOP;
    --打开游标,将来自cusotmers表的SELECT结果集,取值到内存的v_cursor游标中
    OPEN v_cursor FOR
    SELECT * FROM customers WHERE customer_id < 3;
    --读取游标,将内存中的v_cursor游标,取值到v_customer变量中
    LOOP
    FETCH v_cursor
    INTO v_customer;
    EXIT WHEN v_cursor%NOTFOUND;
    dbms_output.put_line('customer_id = ' || v_customer.customer_id ||
    ', first_name = ' || v_customer.first_name ||
    ', last_name = ' || v_customer.last_name);
    END LOOP;
    --关闭游标
    CLOSE v_cursor;
    END;

    五、异常(EXCEPTION)
    异常用于处理PL/SQL程序块中出现的运行时错误。
    例6:ZERO_DIVIDE异常,用数字除以零。

    DECLARE
    v_width INTEGER;
    v_height INTEGER := 0;
    v_area INTEGER := 6;
    BEGIN
    v_width := v_area / v_height;
    dbms_output.put_line('v_width = ' || v_width);
    EXCEPTION
    WHEN zero_divide THEN
    dbms_output.put_line('Division by zero');
    END;
    
    BEGIN
    dbms_output.put_line(1 / 0);
    EXCEPTION
    WHEN zero_divide THEN
    dbms_output.put_line('Division by zero');
    END;

    例7:DUP_VAL_ON_IDNEX异常,向具有唯一索引约束的列中插入重复值。

    BEGIN
    INSERT INTO customers
    (customer_id, first_name, last_name)
    VALUES
    (1, 'Greg', 'Green');
    EXCEPTION
    WHEN dup_val_on_index THEN
    dbms_output.put_line('Duplicate value on an index');
    END;

    例8:INVALID_NUMBER异常,将无效的字符串转换为数字。

    BEGIN
    INSERT INTO customers
    (customer_id, first_name, last_name)
    VALUES
    ('123X', 'Greg', 'Green');
    EXCEPTION
    WHEN invalid_number THEN
    dbms_output.put_line('Conversion of string to number failed');
    END;

    例9:OTHERS异常,可以处理所有异常。

    BEGIN
    dbms_output.put_line(1 / 0);
    EXCEPTION
    WHEN others THEN
    dbms_output.put_line('An exception occurred');
    END;

    六、存储过程(PROCEDURE)
    存储过程是一种命名的、编译好的PLSQL程序块,包含一组SQL和PLSQL语句。
    存储过程可以没有参数,可以有若干输入、输出参数,也可以有多个既作为输入又作为输出的参数,但通常没有返回值。
    存储过程可将业务逻辑集中在数据库中,任何能够访问数据库的程序都可以使用过程。

    创建过程使用CREATE PROCEDURE语句,在关键字PROCEDURE后面是过程名、参数列表;
    过程中的变量声明,不需要DECLARE关键字。
    语法:

    CREATE [OR REPLACE] PROCEDURE procedure_name
    [(parameter_name [IN | OUT | IN OUT] type [, ...])]
    {IS | AS}
    BEGIN
    procedure_body;
    END procedure_name;

    1.无参存储过程
    定义无参存储过程时,存储过程名后不能加();

    例10:创建无参过程

    --创建无参存储过程pro_insertDept,向dept表插入一条记录
    CREATE OR REPLACE PROCEDURE pro_insertDept IS
    BEGIN
    INSERT INTO dept VALUES (77, '市场部', 'JILIN');
    COMMIT;
    dbms_output.put_line('插入新记录成功!');
    END pro_insertDept;
    --声明无参存储过程get_dept_count,该过程返回dept表行数
    DECLARE
    PROCEDURE get_dept_count AS
    dept_count INT;
    BEGIN
    SELECT count(*) INTO dept_count FROM dept;
    dbms_output.put_line('DEPT表的共有记录数:' || dept_count);
    END get_dept_count;
    BEGIN
    get_dept_count;
    END;
    --创建无参存储过程get_dept_count,该过程返回dept表行数
    CREATE OR REPLACE PROCEDURE get_dept_count AS
    dept_count INT;
    BEGIN
    SELECT count(*) INTO dept_count FROM dept;
    dbms_output.put_line('dept表共有' || dept_count || '行记录');
    END get_dept_count;

    例11:调用无参过程
    在块中或是通过EXEC调用存储过程时可以省略();通过CALL调用无参存储过程必须加上()

    -- EXEC
    SQL> exec pro_insertDept;
    PL/SQL procedure successfully completed
    -- CALL
    SQL> call pro_insertDept();
    Method called
    -- BEGIN...END.../
    SQL> begin pro_insertDept; end;
    2 /
    PL/SQL procedure successfully completed

    2.带IN参数的存储过程
    IN 表示输入参数,按值传递,由外部向存储过程传递。

    例12:创建含IN参数的过程

    --创建含IN参数的过程insert_dept,该过程将3个IN模式的变量值插入dept表中
    CREATE OR REPLACE PROCEDURE insert_dept(num_deptno IN NUMBER, var_ename IN VARCHAR2, var_loc IN VARCHAR2) IS
    BEGIN
    INSERT INTO dept VALUES(number_deptno, var_ename, var_loc); COMMIT;
    END insert_dept;
    --创建含IN参数的过程update_product_price,该过程指定ID的产品价格乘以倍数
    CREATE OR REPLACE PROCEDURE update_product_price(p_product_id IN products.product_id%TYPE,
    p_factor IN NUMBER) AS
    v_product_count INTEGER;
    BEGIN
    SELECT count(*)
    INTO v_product_count
    FROM products
    WHERE product_id = p_product_id;
    IF v_product_count = 1 THEN
    UPDATE products SET price = price * p_factor;
    WHERE product_id = p_product_id;
    COMMIT;
    END IF;
    EXCEPTION
    WHEN others THEN
    ROLLBACK;
    END update_product_price;
    --创建含IN参数的过程get_salary,该过程通过员工编号打印员工工资
    CREATE OR REPLACE PROCEDURE get_salary(eno NUMBER) --参数的数据类型不能指定长度
    AS
    salary emp.sal%TYPE;
    BEGIN
    SELECT sal INTO salary FROM emp WHERE empno = eno;
    dbms_output.put_line(eno || '号员工的工资为' || salary);
    EXCEPTION
    WHEN no_data_found THEN
    dbms_output.put_line('没有找到该编号的员工');
    END;

    例13:调用含IN参数的过程

    --位置传递
    BEGIN get_salary(7788);END;
    CALL get_salary(7788);
    BEGIN insert_dept(28,'工程师','洛阳');END;
    CALL update_product_price(1,1.5);
    --名称传递
    BEGIN insert_dept(var_ename => '采购部',var_loc => '成都',num_deptno => 15);END;
    CALL update_product_price(p_factor => 1.3,p_product_id => 2);
    --混合传递
    BEGIN insert_dept(38,var_loc => '济南',var_ename => '测试部');
    CALL update_product_price(1.3,p_product_id => 2);

    3.带OUT参数的存储过程
    OUT 表示输出参数,按引用传递,作为存储过程的输出结果,供外部调用者使用。
    函数RETURN的返回值,直接在SQL窗口中显示;而过程、函数中OUT参数的输出结果,是在SQL旁边的输出窗口显示的,一般用dbms_output.putline()输出信息。

    例14:创建含OUT参数的过程

    --创建含OUT参数的过程select_dept,将从dept表中检索的一行部门信息,存储到2个OUT参数中
    CREATE OR REPLACE PROCEDURE select_dept(num_deptno IN number,
    var_dname OUT dept.dname%TYPE,
    var_loc OUT dept.loc%TYPE) IS
    BEGIN
    SELECT dname, loc
    INTO var_dname, var_loc
    FROM dept
    WHERE deptno = num_deptno;
    EXCEPTION
    WHEN no_data_found THEN
    dbms_output.put_line('该部门编号不存在');
    END select_dept;
    --创建含有IN和OUT参数的过程get_salary,该过程通过员工编号查找工资额,工资额以输出参数返回
    CREATE OR REPLACE PROCEDURE get_salary(eno IN NUMBER, salary OUT NUMBER) AS
    BEGIN
    SELECT sal INTO salary FROM emp WHERE empno = eno;
    dbms_output.put_line(salary);
    EXCEPTION
    WHEN no_data_found THEN
    dbms_output.put_line('没有找到该编号的员工');
    END;

    例15:调用含OUT参数的过程
    调用带OUT参数的过程,必须通过BEGIN..END块,且需要定义变量来保存OUT参数返回的值,不能通过EXEC或CALL调用。

    --调用过程select_dept
    DECLARE
    var_dname dept.dname%TYPE;
    var_loc dept.loc%TYPE;
    BEGIN
    select_dept(20, var_dname, var_loc);
    dbms_output.put_line(var_dname || '位于: ' || var_loc);
    END;
    --调用过程get_salary
    DECLARE salary NUMBER(7, 2);
    BEGIN
    get_salary(7788, salary);
    END;

    4.带IN OUT 参数的存储过程
    即可作输入参数,也可作输出参数。

    例16:创建含IN OUT 参数的存储过程

    --创建带IN OUT参数的过程pro_square,计算平方或平方根
    CREATE OR REPLACE PROCEDURE pro_square(num IN OUT NUMBER, flag IN BOOLEAN) IS
    i INT := 2;
    BEGIN
    IF flag THEN
    num := power(num, i);
    ELSE
    num := sqrt(num);
    END IF;
    END;
    --创建带IN OUT参数的过程get_salary,查找指定员工id的工资
    CREATE OR REPLACE PROCEDURE get_salary(salary IN OUT NUMBER) AS
    BEGIN
    SELECT sal INTO salary FROM emp WHERE empno = salary;
    EXCEPTION
    WHEN no_data_found THEN
    dbms_output.put_line('没有找到该编号的员工');
    END;

    例17:调用带IN OUT参数的存储过程

    --调用过程pro_square
    DECLARE
    no NUMBER(7, 2);
    BEGIN
    no := 25;
    pro_square(no, true);
    dbms_output.put_line('power of 25 is: ' || no);
    pro_square(no, false);
    dbms_output.put_line('square of 25 is: ' || no);
    END;
    --调用过程get_salary
    DECLARE no NUMBER(7, 2);
    BEGIN
    no := 7788; get_salary(no); dbms_output.put_line(no);
    END;

    5.带IN参数默认值的存储过程
    例18:创建带IN参数默认值的存储过程

    CREATE OR REPLACE PROCEDURE insert_dept(num_deptno IN NUMBER,
    var_dname IN VARCHAR2 DEFAULT '综合部',
    var_loc IN VARCHAR2 DEFAULT '北京') IS
    BEGIN
    INSERT INTO dept VALUES (num_deptno, var_dname, var_loc);
    END;

    例19:调用带IN参数默认值的存储过程

    DECLARE
    row_dept dept%ROWTYPE;
    BEGIN
    insert_dept(57, var_loc => '太原');
    COMMIT;
    SELECT * INTO row_dept FROM dept WHERE deptno = 57;
    dbms_output.put_line('部门名称是:《' || row_dept.dname || '》,位置是:《' ||
    row_dept.loc || '');
    END;

    3.查看过程

    4.删除过程

    【参考资料】

    [1] Jason Price.精通Oracle Database 12c SQL&PLSQL编程(第3版).[M].北京:清华大学出版社,2014

  • 相关阅读:
    CSU 1554 SG Value —— 思维
    最优配对问题(集合上的动态规划) —— 状压DP
    Codeforces Round #374 (Div. 2) D. Maxim and Array —— 贪心
    Codeforces Round #373 (Div. 2) C. Efim and Strange Grade —— 贪心 + 字符串处理
    Codeforces Round #369 (Div. 2) D. Directed Roads —— DFS找环 + 快速幂
    Codeforces Round #374 (Div. 2) C. Journey —— DP
    Codeforces Round #363 (Div. 2) D. Fix a Tree —— 并查集
    Codeforces Round #374 (Div. 2) B. Passwords —— 基础题
    Codeforces Round #374 (Div. 2) A. One-dimensional Japanese Crossword —— 基础题
    UVA10129 Play on Words —— 欧拉回路
  • 原文地址:https://www.cnblogs.com/cenliang/p/5124726.html
Copyright © 2011-2022 走看看