Oracle11G-SQL开发指南-11-PL/SQL编程

本文详细介绍了PL/SQL的基础知识,包括块结构、变量声明、条件逻辑、循环控制、游标操作、异常处理、过程与函数创建及调用、包管理和触发器编写等核心内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.  块结构
    [DECLARE declaration_statements ]
    BEGIN
        executable_statements
    [EXCEPTION
        exception_handling_statements
    ]
    END;
   例1:
   DECLARE
     V_WIDTH  INTEGER;
     V_HEIGHT INTEGER := 3;
     V_ARE    INTEGER := 6;
   BEGIN
     V_WIDTH := V_ARE / V_HEIGHT;
     DBMS_OUTPUT.PUT_LINE('v_width=' || V_WIDTH);
   EXCEPTION
     WHEN ZERO_DIVIDE THEN
       DBMS_OUTPUT.PUT_LINE('报错了:Division by zero');
   END;


2.  变量和类型
    变量在DECLARE块中声明;
    声明时要同时包含名称和类型;
    v_id INTEGER;
    v_char VARCHAR2(50);
    v_type table_name.colmnt_name%TYPE;


3.  条件逻辑
    IF、THEN、ELSE、ELSEIF、ENDIF;


4.  循环
    a> 简单循环
        LOOP
            statements
        END LOOP;
结束循环要使用EXIT或EXIT WHEN语句
结束当前循环进行下一次循环可以使用CONTINUE或CONTINUE WHEN语句
    b> WHILE循环
        WHILE condition LOOP
   statements
END LOOP;


    c> FOR循环
        FOR loop_variable IN [REVERSE] lower_bound.. upper_bound LOOP
   statements
END LOOP;


5.  游标cursor
    a> 声明变量,用于存储记录的列值;
    b> 声明游标;
    c> 打开游标;
    d> 一次从游标中取出一个值来,并将列值存储在第1步声明的变量中,进行自定义的操作处理;
    e> 关闭游标;


6.  异常  exception 块中的内容
    EXCEPTION 
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('出现异常:Division by zero');
        ROLLBACK;
        RETURN;


7.  过程 : 一组SQL和pl/sql语句
    a> 创建过程
       CREATE [ OR REPLACE ] PROCEDURE pocedure_name
       [(parameter_name [IN | OUT | IN OUT ] type [, ...])]
       {IS | AS }
       BEGIN
         procedure_body
       END pocedure_name ;
    b> 调用过程:
       call pocedure_name (parameter_name => value);
    c> 获取过程信息 user_procedures 
    d> 删除过程  drop PROCEDURE pocedure_name ;
    e> 查看报错 show errors


8.  函数,与过程相似,就是多一个返回值
    a> 创建函数
       CREATE [ OR REPLACE ] FUNCTION function_name
       [(parameter_name [IN | OUT | IN OUT ] type [, ...])]
       RETURN type
       {IS | AS }
       BEGIN
         function_body
       END function_name ;
    b> 调用函数:与内置函数类似
    c> 获取函数信息 user_procedures 
    d> 删除过程  drop FUNCTION function_name ;


9.  包,把函数和过程组织在一起
    包由两部分组成:规范specification和包体body
    创建包规范:
    CREATE [OR REPLACE ] PACKAGE package_name
    {IS | AS}
        package_specification
    END package_name ;
    创建包体:
    CREATE [OR REPLACE ] PACKAGE BODY package_name
    {IS | AS}
        package_body
    END package_name;


10. 触发器
    CREATE [OR REPLACE] TRIGGER trigger_name
    {BEFORE | ALTER | INSTEAD OF | FOR } trigger_event
    ON table_name
    [FOR EACH ROW]
    [{FORWARD | REVERSE} CROSSEDITION ]
    [{FOLLOWS | PRECEDES} schema.other_trigger]
    [{ENABLE | DISABLE}]
    [WHEN trigger_condition ]
    BEGIN
        trigger_body;
    END trigger_name ;


创建时的is与as区别
是ORACLE为了方便而设置的同义词
在存储过程(PROCEDURE)和函数(FUNCTION)中没有区别;
在视图(VIEW)中只能用AS不能用IS;
在游标(CURSOR)中只能用IS不能用AS。


-------------------------------------------------------
-- 块  声明块,执行块,异常块 
  DECLARE
     V_WIDTH  INTEGER;
     V_HEIGHT INTEGER := 3;
     V_ARE    INTEGER := 6;
   BEGIN
     V_WIDTH := V_ARE / V_HEIGHT;
     DBMS_OUTPUT.PUT_LINE('v_width=' || V_WIDTH);
   EXCEPTION
     WHEN ZERO_DIVIDE THEN
       DBMS_OUTPUT.PUT_LINE('报错了:Division by zero');
     WHEN OTHERS THEN
       DBMS_OUTPUT.PUT_LINE('出现异常:Division by zero');
   END;


-------------------------------------------------------
 --简单循环 ,IF,EXIT WHEN
   DECLARE
      V_COUNT INTEGER := 0;
    BEGIN
      LOOP
        V_COUNT := V_COUNT + 1;
        IF V_COUNT = 3 THEN
          CONTINUE;
        END IF;
        DBMS_OUTPUT.PUT_LINE('当前值为:' || v_count);
        EXIT WHEN V_COUNT = 5;
      END LOOP;
    END;
-------------------------------------------------------
--简单循环,CONTINUE WHEN,EXIT WHEN
    DECLARE
      V_COUNT INTEGER := 0;
    BEGIN
      LOOP
        V_COUNT := V_COUNT + 1;
        CONTINUE WHEN v_count = 3 ;
        DBMS_OUTPUT.PUT_LINE('当前值为:' || v_count);
        EXIT WHEN V_COUNT = 5;
      END LOOP;
    END;
-------------------------------------------------------   
-- while 循环
    DECLARE
      V_COUNT INTEGER := 0;
    BEGIN
      WHILE V_COUNT < 6 LOOP
        V_COUNT := V_COUNT + 1;
        DBMS_OUTPUT.PUT_LINE('当前值为:' || V_COUNT);
      END LOOP;
    END;
-------------------------------------------------------
--for循环


    DECLARE
      V_COUNT INTEGER := 0;
    BEGIN
      FOR V_COUNT IN 1.. 6 LOOP      
        DBMS_OUTPUT.PUT_LINE('当前值为:' || V_COUNT);
      END LOOP;
    END;


-------------------------------------------------------
-- 游标示例1 完整过程
 
    DECLARE
      -- 1:声明变量
      V_PRODUCT_ID PRODUCTS.PRODUCT_ID%TYPE;
      V_NAME       PRODUCTS.NAME%TYPE;
      V_PRICE      PRODUCTS.PRICE%TYPE;
      -- 2:声明游标
      CURSOR V_PRODUCT_CURSOR IS
        SELECT PRODUCT_ID, NAME, PRICE FROM PRODUCTS ORDER BY PRODUCT_ID;
    
    BEGIN
      -- 3: 打开游标
      OPEN V_PRODUCT_CURSOR;
    
      LOOP
      -- 4: 从游标中取数据
        FETCH V_PRODUCT_CURSOR
          INTO V_PRODUCT_ID, V_NAME, V_PRICE;
        EXIT WHEN V_PRODUCT_CURSOR%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE('id值为:' || V_PRODUCT_ID || 'name=:' || V_NAME);
      END LOOP;
      -- 5.关闭游标
      CLOSE V_PRODUCT_CURSOR;
    END;

-------------------------------------------------------
-- 游标示例2 : 结合for循环 不用显示打开和关闭游标
 
    DECLARE
      -- 1:声明变量
      -- 2:声明游标
      CURSOR V_PRODUCT_CURSOR IS
        SELECT PRODUCT_ID, NAME, PRICE FROM PRODUCTS ORDER BY PRODUCT_ID;
    
    BEGIN
      -- 3: 打开游标    
      FOR v_product IN V_PRODUCT_CURSOR LOOP
      -- 4: 从游标中取数据
        DBMS_OUTPUT.PUT_LINE('id值为:' ||v_product.PRODUCT_ID || 'name=:' || v_product.NAME);
      END LOOP;
      -- 5.关闭游标
    END;
 


-------------------------------------------------------
-- 游标示例3 :ref cursor游标 结合open-for语句 灵活使用游标
-- 动态关联结果集的临时对象。即在运行的时候动态决定执行查询。
    
    DECLARE
      -- 1:声明变量
      -- 2:声明游标
      TYPE T_PRODUCT_CURSOR IS REF CURSOR RETURN PRODUCTS%ROWTYPE;
      V_PRODUCT_CURSOR T_PRODUCT_CURSOR;
      V_PRODUCT        PRODUCTS%ROWTYPE;
    
    BEGIN
      -- 3: 打开游标    
      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;
        -- 4: 从游标中取数据
        DBMS_OUTPUT.PUT_LINE('id值为:'|| V_PRODUCT.PRODUCT_ID || 'name=:'||V_PRODUCT.NAME);
      END LOOP;
      -- 5.关闭游标
      CLOSE V_PRODUCT_CURSOR;
    END;


-------------------------------------------------------
-- 游标示例4  无约束游标


    DECLARE
      TYPE T_CURSOR IS REF CURSOR;  --先定义动态游标
      V_CURSOR   T_CURSOR;
      V_PRODUCT  PRODUCTS%ROWTYPE;
      V_CUSTOMER CUSTOMERS%ROWTYPE;
      
    BEGIN
      OPEN V_CURSOR FOR
        SELECT * FROM PRODUCTS WHERE PRODUCT_ID < 5 ;
      LOOP
        FETCH V_CURSOR  INTO V_PRODUCT;   -- 第一次动态使用
        EXIT WHEN V_CURSOR%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE('id值为:' || V_PRODUCT.PRODUCT_ID || 'name=:' || V_PRODUCT.NAME);
      END LOOP;


      OPEN V_CURSOR FOR
        SELECT * FROM CUSTOMERS WHERE CUSTOMER_ID <3 ;
      LOOP
        FETCH V_CURSOR INTO V_CUSTOMER;  -- 第二次动态使用
        EXIT WHEN V_CURSOR%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE('id值为:' || V_CUSTOMER.customer_ID || 'name=:' || V_CUSTOMER.first_name);
      END LOOP;
      EXCEPTION 
        WHEN OTHERS THEN
         DBMS_OUTPUT.PUT_LINE('出现异常:Division by zero');
      
      CLOSE V_CURSOR;
    END;
        
-------------------------------------------------------
-- 过程


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
  -- count the number of products with the
  -- supplied product_id (will be 1 if the product exists)
  SELECT COUNT(*)
  INTO v_product_count
  FROM products
  WHERE product_id = p_product_id;


  -- if the product exists (v_product_count = 1) then
  -- update that product's price
  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;

-------------------------------------------------------
-- 函数1
CREATE OR REPLACE FUNCTION circle_area (
  p_radius IN NUMBER
) RETURN NUMBER AS
  v_pi   NUMBER := 3.1415926;
  v_area NUMBER;
BEGIN
  -- circle area is pi multiplied by the radius squared
  v_area := v_pi * POWER(p_radius, 2);
  RETURN v_area;
END circle_area;


-- 函数2
CREATE OR REPLACE FUNCTION average_product_price (
  p_product_type_id IN INTEGER
) RETURN NUMBER AS
  v_average_product_price NUMBER;
BEGIN
  SELECT AVG(price)
  INTO v_average_product_price
  FROM products
  WHERE product_type_id = p_product_type_id;
  RETURN v_average_product_price;
END average_product_price;


-------------------------------------------------------
-- 包
CREATE OR REPLACE PACKAGE product_package AS
  TYPE t_ref_cursor IS REF CURSOR;
  FUNCTION get_products_ref_cursor RETURN t_ref_cursor;
  PROCEDURE update_product_price (
    p_product_id IN products.product_id%TYPE,
    p_factor     IN NUMBER
  );
END product_package;


-------------------------------------------------------
-- 触发器
CREATE OR REPLACE TRIGGER before_product_price_update
BEFORE UPDATE OF price
ON products
FOR EACH ROW 
when (new.price < old.price * 0.75)
BEGIN
  dbms_output.put_line('product_id = ' || :old.product_id);
  dbms_output.put_line('Old price = ' || :old.price);
  dbms_output.put_line('New price = ' || :new.price);
  dbms_output.put_line('The price reduction is more than 25%');


  -- insert row into the product_price_audit table
  INSERT INTO product_price_audit (
    product_id, old_price, new_price
  ) VALUES (
    :old.product_id, :old.price, :new.price
  );
END before_product_price_update;



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值