PL/SQL

使用PL/SQl

PL/SQl简介

PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言
PL/SQL 是对 SQL 的扩展
支持多种数据类型,如大对象和集合类型,可使用条件和循环等控制结构
可用于创建存储过程、触发器和程序包,给SQL语句的执行添加程序逻辑
与 Oracle 服务器和 Oracle 工具紧密集成,具备可移植性、灵活性和安全性
PL/SQl优点
● 支持 SQL,在 PL/SQL 中可以使用:
(1)数据操纵命令
(2)事务控制命令
(2)游标控制
(4)SQL 函数和 SQL 运算符
● 支持面向对象编程 (OOP)
可移植性,可运行在任何操作系统和平台上的Oralce 数据库
● 更佳的性能,PL/SQL 经过编译执行
与 SQL 紧密集成,简化数据处理。
(1)支持所有 SQL 数据类型
(2)支持 NULL 值
(3)支持 %TYPE 和 %ROWTYPE 属性类型
● 安全性,可以通过存储过程限制用户对数据的访问

PL/SQl块

PL/SQL 分为三个部分,声明部分、可执行部分和异常处理部分
DECLARE

BEGIN

END;

变量常量
给变量赋值有两种方法:
使用赋值语句 :=
使用 SELECT INTO 语句

常量在列名后加constant

declare
-- 声明四个变量,初始化值
  name varchar2(20) := '张三';
  sex varchar2(10);
  -- 声明常量
  age constant number :=20;
  now date := sysdate;
begin
  sex :='男';
  -- sge :=21;常量不能修改
  -- 使用select into 赋值
  select s.name into name from student s where s.id = 2;
  dbms_output.put_line('姓名:'||name||'性别:'||sex||'年龄:'||age||'时间:'||now);
end;

数据类型

标量类型
数字
字符

字符数据类型包括:
char
varchar2
long
raw
long raw

布尔型

此类别只有一种类型,即BOOLEAN类型
用于存储逻辑值(TRUE、FALSE和NULL)
不能向数据库中插入BOOLEAN数据
不能将列值保存到BOOLEAN变量中
只能对BOOLEAN变量执行逻辑操作

日期时间

存储日期和时间数据
常用的两种日期时间类型
DATE
TIMESTAMP

LOB类型
属性类型

用于引用数据库列的数据类型,以及表示表中一行的记录类型
属性类型有两种:
%TYPE - 引用变量和数据库列的数据类型
%ROWTYPE - 提供表示表中一行的记录类型
使用属性类型的优点:
不需要知道被引用的表列的具体类型
如果被引用对象的数据类型发生改变,PL/SQL 变量的数据类型也随之改变

逻辑比较

逻辑比较用于比较变量和常量的值,这些表达式称为布尔表达式
布尔表达式由关系运算符与变量或常量组成
在这里插入图片描述
布尔表达式的结果为TRUE、FALSE或NULL,通常由逻辑运算符AND、OR和NOT连接

控制结构

条件控制
IF 语句
--输入一个成绩,输出成绩等级
declare
   score number;
begin
  -- 接收键盘输入内容
  score := &请输入成绩;
  if score >=90 then 
    dbms_output.put_line('优秀');
  elsif score >=80 then
    dbms_output.put_line('良好');
  elsif score >=70 then
    dbms_output.put_line('中等');
  elsif score >=60 then
    dbms_output.put_line('及格');
  else
    dbms_output.put_line('不及格');
  end if;
end;
CASE 语句
-- 输入成绩等级,输出对应的内容
declare
  score varchar2(4) := '&输入成绩等级(A、B、C、D、E)';
begin
  case score
    when 'A' then 
      dbms_output.put_line('优秀');
    when 'B' then
      dbms_output.put_line('良好') ;
    when 'C' then 
      dbms_output.put_line('中等');
    when 'D' then
      dbms_output.put_line('及格');
    when 'E' then 
      dbms_output.put_line('不及格');
    else
      dbms_output.put_line('输入错误!');
  end case;
end;
循环控制
LOOP 循环
-- loop 计算1~100 的和
declare
   he number :=0;
   i number :=1;
begin
  loop
    he := he + i;
    exit when i = 100;
    i := i + 1;
  end loop;
  dbms_output.put_line('总和为:'||he);
end;
WHILE 循环
-- while 计算1~100 的和
declare
   he number :=0;
   i number :=1;
begin
  --只有符合条件才进入loop循环体
  while i<=100
    loop
    he := he + i;
    i := i + 1;
    end loop;
  dbms_output.put_line('总和为:'||he);
end;
FOR 循环
-- for 计算1~100 的和
declare
  he number := 0;
begin
  --i 的取值从1~100 reverse 循环从后面开始
  for i in reverse 1..100
  loop
    dbms_output.put_line(i);
    he := he + i;
  end loop;
  dbms_output.put_line(he);
end;
顺序控制
GOTO 语句
NULL 语句

异常处理机制

● 在运行程序时出现的错误叫做异常
● 发生异常后,语句将停止执行,控制权转移到 PL/SQL 块的异常处理部分
● 异常有两种类型:
(1)预定义异常 - 当 PL/SQL 程序违反 Oracle 规则或超越系统限制时隐式引发
(2)用户定义异常 - 用户可以在 PL/SQL 块的声明部分定义异常,自定义的异常通过 RAISE 语句显式引发

-- 系统内置异常使用
declare
  i number :=10;
begin
  dbms_output.put_line('i/0='||(i/0));
-- 异常处理部分
exception
  -- 根据不同的异常类型进行处理,zero_divide 除数为0 异常处理
  when zero_divide then
    dbms_output.put_line('除数不能为0');
  when others then
    dbms_output.put_line('其他异常');
end;

-- 用户自定义异常使用
declare
  -- 自定义异常,用关键字 exception 声明
  sex_exception exception;
  sex varchar2(10);
  age_exception exception;
  age number;
begin
  sex := '&请输入性别:';
  age := &请输入年龄:;
  if sex not in('男','女') then
    -- 抛出自定义异常
    raise sex_exception;
  end if;
  if age not between 0 and 150 then
    raise age_exception;
  end if;
exception 
  -- 捕获处理自定义异常
  when sex_exception then
--  dbms_output.put_line('性别只能为男或者女');
    -- 弹出自定义错误信息窗口,第一个参数是错误代码,取值范围是-20001~-20999,第二个参数是错误信息描述,最大长度2048字节
    raise_application_error(-20001,'性别只能为男或者女');
  when age_exception then
--  dbms_output.put_line('年龄只能输入0~150之间');
    raise_application_error(-20002,'年龄只能输入0~150之间');
end;

常见异常类型

CURSOR_ALREADY_OPEN 试图"OPEN"一个已经打开的游标
DUP_VAL_ON_INDEX 试图向有"UNIQUE"中插入重复的值
INVALID_CURSOR 试图对以关闭的游标进行操作
INVALID_NUMBER 在SQL语句中将字符转换成数字失败
LOGIN_DENIED 使用无效用户登陆
NO_DATA_FOUND 没有找到数据时
TIMEOUT_ON_RESOURCE Oracle等待资源期间发生超时
TOO_MANY_ROWS "SELECT INTO"返回多行时
VALUE_ERROR 当出现赋值错误
ZERO_DIVIDE 除数为零

总结

PL/SQL 是一种可移植的高性能事务处理语言
PL/SQL 块由声明部分、可执行部分和异常处理部分组成
PL/SQL 数据类型包括标量数据类型
控制结构包括条件控制、循环控制和顺序控制
PL/SQL 支持动态 SQL
运行时出现的错误叫做异常
异常可以分为预定义异常和用户定义的异常

游标

逐行处理查询结果,以编程的方式访问数据
游标的类型:
隐式游标、显式游标、REF游标

隐式游标

● 在PL/SQL中使用DML语句时自动创建隐式游标
隐式游标自动声明、打开和关闭,其名为 SQL
● 通过检查隐式游标的属性可以获得最近执行的DML 语句的信息
隐式游标的属性有:
(1)%FOUND – SQL 语句影响了一行或多行时为 TRUE
(2)%NOTFOUND – SQL 语句没有影响任何行时为TRUE
(3)%ROWCOUNT – SQL 语句影响的行数
(4)%ISOPEN - 游标是否打开,始终为FALSE

-- 隐式游标常用属性使用,隐式游标固定名称sql,在执行dml语句时自动创建,打开,关闭
declare

begin
  update emp e set e.salary = e.salary + &新加工资 where e.employee_id = &员工编号;
  -- 影响到数据行返回true ,不影响返回false 和 sql%notfound相反
  if sql%found then
    --sql%rowcount影响到的行数
    dbms_output.put_line('成功更新'||sql%rowcount||'行数据');
  end if;
  commit;
  -- sql%isopen 判断游标是否关闭,永远是false
  if sql%isopen then
      dbms_output.put_line('游标状态打开');
  else
      dbms_output.put_line('游标状态关闭');
  end if;
end;

显式游标

显式游标在 PL/SQL 块的声明部分定义查询,该查询可以返回多行

-- 使用显示游标遍历表所有记录
declare
  student_row student%rowtype;
  --使用关键字cursor声明游标变量student_cursor并初始化值
  cursor student_cursor is select * from student order by id;
begin
  -- 打开游标
  open student_cursor;
  loop
    -- 逐行读取
    fetch student_cursor into student_row;
    --游标中没有数据退出循环
    exit when student_cursor%notfound;
    dbms_output.put_line('编号:'||student_row.id||'姓名:'||student_row.name);
  end loop;
  -- 关闭游标
  close student_cursor;
end;

-- 带参数的显示游标,根据部门编号查询员工信息
declare
  emp_row emp%rowtype;
  -- 声明带参数的游标,多个参数逗号隔开
  cursor emp_cursor(dept_no emp.department_id%type)is select e.* from emp e where e.department_id = dept_no;
begin
  --打开游标,传递对应的参数值
  open emp_cursor(&部门编号);
  loop
    fetch emp_cursor into emp_row;
    exit when emp_cursor%notfound;
    dbms_output.put_line('员工编号:'||emp_row.employee_id||' 工资:'||emp_row.salary);
  end loop;
  close emp_cursor;
end;

循环游标

-- 循环游标=显示游标+for循环
declare
  emp_row emp%rowtype;
  cursor emp_cursor is select * from emp;
begin
  for emp_row in emp_cursor
    loop
      dbms_output.put_line('员工编号:'||emp_row.employee_id||' 工资:'||emp_row.salary);      
    end loop;
end;

REF游标

REF 游标用于处理运行时才能确定的动态 SQL 查询的结果
REF 游标和游标变量 **
REF 游标
游标变量**用于处理运行时动态执行的 SQL 查询
创建游标变量需要两个步骤:
声明 REF 游标类型
声明 REF 游标类型的变量
用于声明 REF 游标类型的语法为:
TYPE <ref_cursor_name> IS REF CURSOR
[RETURN <return_type>];

-- 创建REF游标
declare
  -- 声明ref游标类型emp_ref_cursor,指定ret游标返回类型是emp表行类型
  type emp_ref_cursor is ref cursor return emp%rowtype;
  -- 使用emp_ref_cuesor类型声明游标变量emp_cursor
  emp_cursor emp_ref_cursor;
  emp_row emp%rowtype;
begin
  --打开游标并初始化值
  open emp_cursor for select e.* from emp e;
  loop
    fetch emp_cursor into emp_row;
    exit when emp_cursor%notfound;
    dbms_output.put_line('员工编号:'||emp_row.employee_id||' 工资:'||emp_row.salary);      
  end loop;
  close emp_cursor;
end;
-- 使用ref游标执行动态sql
declare
  -- 声明ref游标类型emp_ref_cursor,执行动态sql游标不能有返回值
  type emp_ref_cursor is ref cursor; 
  -- 使用emp_ref_cuesor类型声明游标变量emp_cursor
  emp_cursor emp_ref_cursor;
  emp_row emp%rowtype;
begin
  --打开游标并初始化值,使用动态sql赋值,动态sql用单引号括起来,参数用占位符,using 赋值
  open emp_cursor for 'select e.* from emp e where e.department_id = :1' using &部门编号;
  loop
    fetch emp_cursor into emp_row;
    exit when emp_cursor%notfound;
    dbms_output.put_line('员工编号:'||emp_row.employee_id||' 工资:'||emp_row.salary);      
  end loop;
  close emp_cursor;
end;

总结

游标作用:用于处理查询结果集中的数据
游标类型有:隐式游标、显式游标和 REF 游标
隐式游标由 PL/SQL 自动定义、打开和关闭
显式游标用于处理返回多行的查询
显式游标可以删除和更新活动集中的行
要处理结果集中所有记录时,可使用循环游标
在声明 REF 游标时,不需要将 SELECT 语句与 其关联

子程序和程序包

子程序

● 命名的 PL/SQL 块,编译并存储在数据库中。
● 子程序的各个部分:
(1)声明部分
(2)可执行部分
(3)异常处理部分(可选)
● 子程序的分类:
(1)过程 - 执行某些操作
(2)函数 - 执行操作并返回值
● 子程序的优点:
(1)模块化
将程序分解为逻辑模块
(2)可重用性
可以被任意数目的程序调用
(3)可维护性
简化维护操作
(4)安全性
通过设置权限,使数据更安全

过程 procedure

过程参数的三种模式:
IN
用于接受调用程序的值
默认的参数模式
OUT
用于向调用程序返回值
IN OUT
用于接受调用程序的值,并向调用程序返回更新的值

-- 创建存储过程,根据员工编号输出员工信息
create or replace procedure find_emp_no(emp_no emp.employee_id%type)
is
  emp_row emp%rowtype;
begin
  select e.* into emp_row from emp e where e.employee_id = emp_no;
  dbms_output.put_line('编号'||emp_row.employee_id||'姓名'||emp_row.salary);
end;
-- 调用存储过程
-- 方式一,使用pl/sql程序调用
declare

begin
  -- 过程名称和参数调用
  find_emp_no(&员工编号);
end;
-- 方式二,在命令行窗口执行execute find_emp_no(100);如果控制台不显示输出结果,执行set serveroutput on

-- 创建存储过程,根据员工编号获取薪资,参数模式in默认的,用来调用者传入,out用来传出去给调用过程者使用
create or replace procedure get_salary_by_empno(emp_no in emp.employee_id%type,salary out emp.salary%type)
is

begin
  select e.salary into salary from emp e where e.employee_id = emp_no;
end;
-- 调用
declare
  salary emp.salary%type;
begin
  dbms_output.put_line('工资'||salary);
  get_salary_by_empno(&员工编号,salary);
  dbms_output.put_line('工资'||salary);
end;

函数 function

-- 创建函数,根据员工编号返回员工工资
create or replace function get_salary_by_emp_no(emp_no emp.employee_id%type) return emp.salary%type
is
  salary emp.salary%type;
begin
  select e.salary into salary from emp e where e.employee_id = emp_no;
  return salary;-- ruturn 返回一个值,类型必须跟声明时一致
end;
--函数调用
-- 方式一,pl/sql程序块调用
declare
  salary emp.salary%type;
begin
  salary := get_salary_by_emp_no(&员工编号);
  dbms_output.put_line('工资'||salary);
end;
-- 方式二,使用dual伪表
select get_salary_by_emp_no(101) from dual;
-- 创建函数,实现根据部门编号返回总人数total_by_dept_no
create or replace function total_by_dept_no(emp_date emp.department_id%type) return number
is
  peonumber number;
begin
  select count(e.employee_id) into peonumber from emp e where e.department_id = emp_date;
  return peonumber;
end;
-- 调用
declare
  peonumber number;
begin
  peonumber := total_by_dept_no(&输入部门);
  dbms_output.put_line('部门人数'||peonumber);
end;
select total_by_dept_no(50) from dual;

函数和过程的联系与区别

相同点:
都是子程序,封装pl/sql语句块,可以接收传递参数,拥有封装、模块化、可复用性、安全性作用,都可以使用pl/sql程序块调用
不同点:
函数有返回值,过程参数有三种模式,过程本身不返回值,但是可以通过参数out模式回写多个值,函数使用select 函数名 from dual 调用,过程在命令窗口使用execute 过程名 调用

程序包

程序包是对相关过程、函数、变量、游标和异常等对象的封装
程序包由规范和主体两部分组成
程序包的优点
模块化
更轻松的应用程序设计
信息隐藏
新增功能
性能更佳
程序包中的游标
游标的定义分为游标规范和游标主体两部分
在包规范中声明游标规范时必须使用 RETURN 子句指定游标的返回类型
RETURN子句指定的数据类型可以是:
用 %ROWTYPE 属性引用表定义的记录类型
程序员定义的记录类型

-- 创建程序包规范
create or replace package my_pack
as
  procedure find_emp_no(emp_no emp.employee_id%type);
  procedure get_salary_by_empno(emp_no in emp.employee_id%type,salary out emp.salary%type);
  procedure swap(number_one in out number,number_two in out number);
  function get_salary_by_emp_no(emp_no emp.employee_id%type) return emp.salary%type;
  function total_by_dept_no(emp_date emp.department_id%type) return number;
  function total_sum(a number,b number) return number;
end my_pack; 

-- 创建程序包主体
create or replace package body my_pack
as
--------------------------find_emp_no开始---------------------------------------
  procedure find_emp_no(emp_no emp.employee_id%type)
  is
    emp_row emp%rowtype;
  begin
    select e.* into emp_row from emp e where e.employee_id = emp_no;
    dbms_output.put_line('编号'||emp_row.employee_id||'姓名'||emp_row.salary);
  end find_emp_no;
---------------------------get_salary_by_empno开始-----------------------------
  procedure get_salary_by_empno(emp_no in emp.employee_id%type,salary out emp.salary%type)
  is

  begin
    select e.salary into salary from emp e where e.employee_id = emp_no;
  end get_salary_by_empno;
----------------------------swap-------------------------
  procedure swap(number_one in out number,number_two in out number)
  is
    swap_num number;
  begin
    swap_num := number_one;
    number_one := number_two;
    number_two := swap_num;
  end swap;
-----------------------------get_salary_by_emp_no-----------
  function get_salary_by_emp_no(emp_no emp.employee_id%type) return emp.salary%type
  is
    salary emp.salary%type;
  begin
    select e.salary into salary from emp e where e.employee_id = emp_no;
    return salary;-- ruturn 返回一个值,类型必须跟声明时一致
  end get_salary_by_emp_no;
------------------------------total_by_dept_no----------
  function total_by_dept_no(emp_date emp.department_id%type) return number
  is
    peonumber number;
  begin
    select count(e.employee_id) into peonumber from emp e where e.department_id = emp_date;
    return peonumber;
  end total_by_dept_no;
-------------------------------total_sum-------------------
  function total_sum(a number,b number) return number
  is
    tosum number :=0;
  begin
    if a<b then
     for i in a..b
      loop
        tosum := tosum+i;
      end loop;
    else
      for i in b..a
      loop
        tosum := tosum+i;
      end loop;
    end if;
    return tosum;
  end total_sum;
------------------------------------------------------------------
end my_pack;
  
  
-- 程序包调用
declare
  salary emp.salary%type;
  num1 number := 100;
  num2 number := 200;
  total number;
begin
  my_pack.find_emp_no(100);
  my_pack.get_salary_by_empno(100,salary);
  dbms_output.put_line('工资'||salary);
  dbms_output.put_line('num1:'||num1||',num2:'||num2);
  my_pack.swap(num1,num2);
  dbms_output.put_line('num1:'||num1||',num2:'||num2);
  dbms_output.put_line('工资:'||my_pack.get_salary_by_emp_no(100));
  dbms_output.put_line('总人数:'||my_pack.total_by_dept_no(90));
  dbms_output.put_line('总和:'||my_pack.total_sum(1,100));  
end;

-- 创建程序包规范,输入部门编号输出所有员工
create or replace package emp_pack
as
  -- 声明一个游标,指定返回值类型,即游标中存放的数据类型
  cursor emp_cursor(deptno emp.department_id%type) return emp%rowtype;
  -- 根据部门编号输出所有员工信息
  procedure get_emps_by_deptno(deptno emp.department_id%type);
  -- 根据部门编号获取总员工数
  function total(deptno emp.department_id%type) return number;
end emp_pack;

-- 创建程序包主体
create or replace package body emp_pack
as
  cursor emp_cursor(deptno emp.department_id%type) return emp%rowtype 
    is select e.* from emp e where e.department_id=deptno;
    -------------------------------------------------------------------
  procedure get_emps_by_deptno(deptno emp.department_id%type)
    is
      emp_row emp%rowtype;
    begin
      -- 打开游标
      open emp_cursor(deptno);
        loop
          fetch emp_cursor into emp_row;
          exit when emp_cursor%notfound;
          dbms_output.put_line('编号:'||emp_row.employee_id||'工资:'||emp_row.salary);
        end loop;
      close emp_cursor;
    end get_emps_by_deptno;
  -----------------------------------------------------------------------
  function total(deptno emp.department_id%type) return number
    is
      total_num number;
    begin
      select count(*) into total_num from emp e where e.department_id = deptno;
      return total_num;
    end total;
end emp_pack;

--调用
declare
  dept emp.department_id%type := &输入部门;
begin
  dbms_output.put_line(dept||'部门人数总和:'||emp_pack.total(90));
  dbms_output.put_line('成员如下');
  emp_pack.get_emps_by_deptno(90);
end;

总结

子程序是命名的 PL/SQL 块,可带参数并可在需要时随时调用
有两种类型的PL/SQL子程序,即过程和函数
过程用户执行特定的任务,函数用于执行任务并返回值
程序包是对相关类型、变量、常量、游标、异常、过程和函数等对象的封装
程序包由两部分组成,即包规范和包主体
使用程序包的优点是:模块化、更轻松的程序设计、信息隐藏、新增功能以及性能更佳

触发器

触发器是当特定事件出现时自动执行的存储过程
● 特定事件可以是执行更新的DML语句和DDL语句
触发器不能被显式调用
● 触发器的功能:
(1)自动生成数据
(2)自定义复杂的安全权限
(3)提供审计和日志记录
(4)启用复杂的业务逻辑
创建触发器的语法

CREATE [OR REPLACE] TRIGGER trigger_name
AFTER | BEFORE | INSTEAD OF
[INSERT] [[OR] UPDATE [OF column_list]] 
[[OR] DELETE]
ON table_or_view_name
[REFERENCING {OLD [AS] old / NEW [AS] new}]
[FOR EACH ROW]
[WHEN (condition)]
pl/sql_block;

触发器的组成部分
触发器由三部分组成:
(1)触发器语句(事件)
定义激活触发器的 DML 事件和 DDL 事件
(2)触发器限制
执行触发器的条件,该条件必须为真才能激活触发器
(3)触发器操作(主体)
包含一些 SQL 语句和代码,它们在发出了触发器语句且触发限制的值为真时运行

-- 创建触发器,在删除学生记录之后触发
create or replace trigger student_trigger
after  -- 后置触发器
delete  --删除操作
on student  --作用的表名称
for each row --行级触发器,影响一行触发一次,如果不写,语句级触发器,执行一条语句不管影响多少行只触发一次
--pl/sql语句块
begin
  -- :old 指旧的记录行对象,获取该行的所有字段值,:new值新的记录行对象
  dbms_output.put_line('学生记录【'||:old.id||'】被删除');
end;

select * from student order by id;

delete from student where id <= 5;
commit;

-- 创建触发器,对学生记录新增、修改、删除操作之后进行触发
create or replace trigger stu_tirgger.
after
insert or update or delete
on student
for each row
  
begin
  -- 新增操作
  if inserting then
    dbms_output.put_line(sysdate||'学生记录【'||:new.name||'】新增成功');
  --修改操作
  elsif updating then
    dbms_output.put_line(sysdate||'学生记录【'||:old.id||'】密码由【'||:old.password||'】改成新密码【'||:new.password||'】');
  -- 删除操作
  elsif deleting then
    dbms_output.put_line(sysdate||'学生记录【'||:old.id||'】被删除');
  end if;
end;

-- 创建触发器,只能在12点~13点之间新增、修改、删除表
create or replace trigger stu_trigger1
before
insert or delete or update
on student
for each row
  
begin
  if to_char(sysdate,'hh24')!=12 then
    raise_application_error('-20001','学生记录只能在12点~13点之间进行操作');
  end if;
end;


--禁用触发器
alter trigger stu_trigger1 disable;
-- 启用触发器
alter trigger stu_trigger1 enable;
-- 删除触发器
drop trigger stu_trigger1;


--创建instead of 触发器,对视图数据进行修改,针对于包含来自包含多个表的字段的视图数据修改
create or replace trigger view_emp_trigger
instead of
insert or update or delete 
on view_emp
for each row
  
begin
  if inserting then
    dbms_output.put_line('新增操作');
  elsif updating then
    update dept d set d.department_name = :new.dept_name where d.department_id = (select e.department_id from emp e where e.employee_id = :old.id);
  elsif deleting then 
    dbms_output.put_line('删除操作');  
  end if;
end;


-- 模式触发器,用户级别,主要用在ddl 语句中,创建、修改、删除对象时触发
create or replace trigger obj_trigger
after -- 后置触发器
drop or alter or create --  删除对象
on schema -- 作用在模式上,当前用户
begin
  dbms_output.put_line('当前对象:'||ora_dict_obj_owner||'对象名称:'||ora_dict_obj_name||',对象类型:'||ora_dict_obj_type||',操作时间:'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'));
end;

drop table student_bak20210806;
create table test(
  id number,
  name varchar2(10)
);
create index idx_test_name on test(name);
drop index idx_test_name;
drop table test;

总结

触发器是当特定事件出现时自动执行的存储过程
触发器分为 DML 触发器、DDL 触发器和数据库级触发器三种类型
DML 触发器的三种类型包括行级触发器、语句级触发器和 INSTEAD OF 触发器

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值