游标和触发器

存储架构 2018-03-13

一、游标

  • SQL语言是面向集合的,是对指定列的操作。如果要对列中的指定行进行操作,就必须使用游标。
  • 当在PL/SQL块中执行查询语句(SELECT) 和数据操纵语句(DML) 时,Oracle会为其分配一个上下文区(Context Area)
  • 游标是指向上下文区的指针,它为应用提供了一种对具有多行数据查询结果集中的每一行数据分别进行单独处理的方法

显式游标

游标分为显式游标和隐含游标两种

  • 隐含游标用于处理SELECT INTO和DML语句
  • 显式游标则用于处理S ELECT语句返回的多行数据
  1. 使用显式游标

定义游标

CURSOR cursor_ name IS select statement;

打开游标

OPEN cursor name;

提取数据

FETCH cursor_name INTO variable1,variable... ;

FETCH cursor_name bulk collect into collect1..;

关闭游标

CLOSE cursor name;

代码:

--创建游标
declare
cursor 游标名称 is select * from 表名;
变量名 表名%rowtype;
begin
  open 游标名;--打开游标
  loop
    fetch 游标名 into 变量名;--提取游标
    exit when 游标名%notfound;
    dbms_output.put_line(变量名.列名);
    end loop;
   close 游标名;--关闭游标
end;

显示游标属性

显式游标属性用于返回显式游标的执行信息

  • 游标属性使用格式为: 游标名+ 属性名
  • %ISOPEN

用于确定游标是否已经打开。如果游标已经打开,则返回值为TRUE; 否则返回FALSE

  • %FOUND

检查是否从结果集中提取到数据。如果提取到数据,则返回值为TRUE; 否则返回FALSE

  • %NOTFOUND

与%FOUND属性恰好相反,如果提取到数据,则返回值为FALSE; 否则返回TRUE

  • %ROWCOUNT

返回到当前行为止已经提取到的实际行数

参数游标

参数游标是指带有参数的游标。在定义了参数游标之后,使用不同参数值多次打开游标可以生成不同的结果集。

代码:

--参数游标
declare
cursor cursor_wxn(x_empno number)--定义参数(形参)
 is 
 select * from emp where empno=x_empno;
v_name emp%rowtype;
begin
  open cursor_wxn(7369);--(实参)
  loop
    fetch cursor_wxn into v_name;
    exit when cursor_wxn%notfound;
    dbms_output.put_line(v_name.ename);
    end loop;
   close cursor_wxn;
end;

游标for循环

游标for循环是在pl/sql块中使用游标的最简单方式,它可以简化对游标的处理。当使用游标for循环时,oracle会隐含的打开游标,提取游标数据并关闭游标。

代码:

--游标for循环
declare
v_name emp%rowtype;
cursor cursor_wxn
is 
select * from emp;
begin
  for v_name in cursor_wxn loop
    dbms_output.put_line(v_name.ename);
    end loop;
end;

上面代码中无须进行取值和关闭的操作,游标for循环可以自己进行。

下面还有一个更为简单的游标for循环,参考上面的代码进行读阅:

--简单for
begin
  for v_name in (select * from emp) loop
    dbms_output.put_line(v_name.ename);
    end loop;
end;

使用游标变量

代码实例:

declare
type youbiao_bianliang is ref cursor;--变量类型
cursor_varisble youbiao_bianliang;--定义游标类型的变量
v_name emp%rowtype;--变量
begin
open cursor_varisble
for select * from emp where empno=7788;
  loop
    fetch cursor_varisble into v_name;
    exit when cursor_varisble%notfound;
    dbms_output.put_line(v_name.ename);
    end loop;
   close cursor_varisble;
end;

隐含游标

作用 :用属性进行一些判断(一种判断方式)

含义 :当执行一条DML语句或者SELECT...INTO语句时,都会创建一个隐含游标。

隐含游标的名称是SQL,不能对SQL游标显示执行OPEN、FETCH和CLOSE语句。

Oracle隐式地打开、提取,并总是自动地关闭SQL游标。

属性

  1. SQL%FOUND:只有DML语句影响一行或多行时, SQL%FOUND 属性才返回true。
  2. SQL%NOTDOUND:如果DNL语句没有影响行数,此属性将返回false。
  3. SQL%ROWCOUNT:返回DML影响的行数,如果DML语句没有影响行则返回0.
  4. SQL%ISOPEN:此属性用于判断SQL游标是否已经打开。在执行SQL语句之后,Oracle自动关闭SQL游标,所以隐含游标的SQL%ISOPEN属性始终为false。

简单示例1:

-- 隐含游标
begin
  delete from emp where empno=1;
  if sql%notfound then 
    dbms_output.put_line('找不到记录');
  else
    dbms_output.put_line('记录');
  end if;
end;

示例2:

declare
a number:=1;
begin
  delete from emp where empno=a;
  if sql%notfound then
    dbms_output.put_line('没有改变');
  else
    dbms_output.put_line('改变');  
  end if;
end;

二、触发器

  • 触发器组成

1、触发事件

DML或DDL语句。

2、触发时间

是在触发事件发生之前(before) 还是之后(after) 触发

3、触发操作

使用PL/SQL块进行相应的数据库操作

4、触发对象

表、视图、模式、数据库

5、触发频率

触发器内定义的动作被执行的次数,包括语句级和行级ji。

  • 限制

1、触发器不接受参数

2、一个表上最多可有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个。并各触发器之间不能有矛盾。

3、一个表上的触发器越多,该表上的DM操作的性能影响就越大

4、触发器代码的大小不能超过32K。如需要大量的代码创建触发器,则首先创建过程,然后在触发器中使用CALL语句调用过程

5、触发器代码只能包含SELECT、INSERT、UPDATE和DELETE语句,

6、不能包含DDL语句(CREATE、ALTER和DROP) 和事务控制语句(COMMIT、ROLLBACK和SAVEPOINT)

  • 创建触发器

语句触发器
1、语句触发器是指当执行DML语句时被隐含执行的触发器
2、如果在表上针对某种DML操作创建了语句触发器,则当执行DML操作时会自动地执行触发器的相应代码
3、为了审计DML操作,或者确保DML操作安全执行时,可以使用语句触发器

触发器用途很多,例如用户清算购物车后将会触发待收货的数据库

代码示例:

--创建触发器
create or replace trigger tri_test
before--触发之前
update or delete--更新或删除
on emp
for each row--对行进行操作
  begin
    dbms_output.put_line(:old.sal);--old表示数据库旧值
    insert into demo(id) values (:new.sal);--new新值
  end;

update emp set sal=888 where empno=7788;
commit;
--代码解释:先执行创建触发器代码后,再执行最后的更新语句。当更新恩平、表后将会输出数据库中本来存放的值,并且触发添加语句在demo表中插入一条语句。

自定义异常,触发器 拦截

简单代码示例1:

-- 触发器  拦截
create or replace trigger tri_test
before
update or delete
on emp
for each row
  begin
    if to_char(sysdate,'yyyy-mm-dd')='2018-03-13' then--将系统日期转化为字符类型
      -- 自定义异常,
      raise_application_error(-20000,'今天不能修改数据');-- 负20000之前的异常都已经被定义
    end if;
  end;

update emp set sal=777 where empno=7788;
commit;
--触发器创建后,执行最后代码,将会有异常提示:今天不能修改数据

示例2:

create or replace trigger tri_test
before
update or delete or insert
on emp
for each row
  begin
    case
    when updating then
       raise_application_error(-20000,'今天不能修改');
    when inserting then
      raise_application_error(-20001,'今天不能插入');
    when deleting then
      raise_application_error(-20000,'今天不能删除');
    end case;
  end;

update emp set sal=777 where empno=7788;
insert into emp (empno) values (123);
commit;

您可能感兴趣的

SQL Server 2017 Temporal Enhancements SQL Server 2017 Temporal Enhancements October 12, 2017 Leave a comment One of the most popular features in my talks about SQL Server 2016 has...
Big SQL Workload Management Stage 1 – Monitoring by Nailah Bissoon Senior Big SQL Technical Architect The first stage of implementing a customized workload management (WLM) configuration is to mo...
R connection to MS SQL Using R I am trying to connect to MS SQL 2014 on an Azure VM (not windows authentication) library(RODBC) conn <- 10="" odbcdrive...
How to Use the INSERT Command in SQL Server 2017 In this article, you will learn how to insert data into a table in SQL Server. The INSERT INTO statement is used to insert new records in a table....
SQL Server gets non-matching values &ZeroWidth... Here's the scenario: In a SQL Server 2008 R2 database, Table A has StudyID, VisitCode and VisitSequenceNumber. Table B has StudyID, SubjectID and Visi...
0
博客园精华区

责编内容来自:博客园精华区 (本文源链)
阅读提示:酷辣虫无法对本内容的真实性提供任何保证,请自行验证并承担相关的风险与后果!
本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。