PL/SQL NEXTVAL DUAL表


dual表是个虚拟表,你在操作大多数Oracle对象的时候都可以使用这个表,比如sequence,sysdate等等。
比如:
select sysdate from dual
select seq1.nextval from dual

----------------------------------------------------------------------------------------------------------------------

DUAL表是一个奇特的小结构。这个表驻留于SYS模式中,PL/SQL开发人员用它来访问那些PL/SQL自身不提供的SQL特定功能。

DUAL表的最常见应用就是生成和检索一个序列中的下一个数值,通常是用于一个表的主关键字,如下所示: 

 

SELECT employee_seq.NEXTVAL
   INTO :employee.employee_id
   FROM DUAL;

 

Oracle不允许我们直接在PL/SQL代码中引用employee_seq.NEXTVAL;而是必须从一个SELECT语句中调用它。为什么我们要为这一操作使用DUAL表呢?因为它只有唯一一个行(或者应该只有一行)。 NEXTVAL操作符于是自该序列返回下一个(也是唯一的一个)取值。不幸的是,经常会听到参加我们研讨会的人们说到此DUAL表不至一行的情况。在这种情况下,我以前的查询将会出现TOO_MANY_ROWS错误而失败。更糟的情况是,PL/SQL中某些内建的函数,如USER也可能失败,从Oracle数据所提供的stdbody.sql文件中所取出的这一代码中可以清楚地看出这一点:

FUNCTION USER
    RETURN VARCHAR2
  IS
    c VARCHAR2 (255);
  BEGIN
     SELECT USER
     INTO c
     FROM SYS.DUAL;
 
    RETURN c;
 END;

 

如果(a)你依靠DUAL表来生成序列值和(b)你不能保证DUAL表中的行数不超过一行,那么就很难拥有一个自管理式的代码基础。当然,你可以定义一个用于DUAL表的触发器,以防止任何向DUAL表中插入多于一行数据的尝试。但是,为SYS所拥有的表创建用户定义的触发器是一个禁忌。那么,如果开发人员希望避免使用DUAL表,那他们应当怎么做呢?创建并使用他们自己的单行表,并使其具有与DUAL的结构相同的结构。

代码清单5 给出了创建这样一个表的代码和为该表定义一个触发器以保证其只能包含一行数据。

定义了onerow后,我现在可以取得我的下一个主关键字值,如下所示:

SELECT employee_seq.NEXTVAL
  INTO :employee.employee_id
  FROM onerow;

 

因为我对onerow的内容有更多的控制,所以相对于从DUAL中进行查询来说,这是一个更好的解决方案。然而,它还不太理想。如果Oracle数据库的未来版本允许在PL/SQL中直接引用<sequence>.NEXTVAL,那么情况会如何呢? 我将坚持用所有这些现在过时的代码,我可能希望用更简单(且更有效)的代码来代替这些代码:

 

:employee.employee_id := employee_seq.NEXTVAL;

于是,作为使我的应用程序免于被破坏并且易于随着时间的推移而进行更新的最后一步,我将我的查询隐藏于一个"一般"函数之后,此函数利用自有的动态SQL来一般地获得任意序列的下一个值,如代码清单6所示。

现在我可以只用下面的代码就可以获得我的主关键值:

:employee.employee_id := next_pky ('employee_seq');

 

并且,当Oracle数据库取消关于引用NEXTVAL的限制之后,我可以在这一个函数中修改实施;在重新编译后,我的全部代码就可以更新以便使用Oracle数据库的最新功能。尽管这一步骤不会导致100%的自管理,但它确实有助于将你的应用程序基础达到"最少管理"的状态。

你甚至可以利用自有的动态SQL将所有这些步骤组合成一个单一的过程,它将在你的模式中设置对DUAL表的替换操作。  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个 Oracle PL/SQL 的 INSTEAD OF 触发器示例: 假设我们有一个名为 `employees` 的和一个名为 `employees_log` 的。我们想要在 `employees` 上进行一些操作时,自动将相应的日志信息插入到 `employees_log` 中。我们可以使用 INSTEAD OF 触发器来实现这一点。 首先,我们需要创建一个 `employees_log` ,用于存储日志信息。可以使用以下 SQL 语句创建这个: ```sql CREATE TABLE employees_log ( id NUMBER(10) NOT NULL, employee_id NUMBER(10) NOT NULL, action VARCHAR2(100) NOT NULL, log_date DATE NOT NULL ); ``` 然后,我们可以创建一个 INSTEAD OF 触发器来在 `employees` 上进行操作时,自动将相应的日志信息插入到 `employees_log` 中。以下是这个触发器的示例代码: ```sql CREATE OR REPLACE TRIGGER employees_trigger INSTEAD OF INSERT OR UPDATE OR DELETE ON employees FOR EACH ROW DECLARE v_action VARCHAR2(100); BEGIN IF INSERTING THEN v_action := 'insert'; INSERT INTO employees_log (id, employee_id, action, log_date) VALUES (employees_log_seq.nextval, :new.id, v_action, SYSDATE); INSERT INTO employees (id, name, salary) VALUES (employees_seq.nextval, :new.name, :new.salary); ELSIF UPDATING THEN v_action := 'update'; INSERT INTO employees_log (id, employee_id, action, log_date) VALUES (employees_log_seq.nextval, :old.id, v_action, SYSDATE); UPDATE employees SET name = :new.name, salary = :new.salary WHERE id = :old.id; ELSIF DELETING THEN v_action := 'delete'; INSERT INTO employees_log (id, employee_id, action, log_date) VALUES (employees_log_seq.nextval, :old.id, v_action, SYSDATE); DELETE FROM employees WHERE id = :old.id; END IF; END; ``` 该触发器被定义为一个 INSTEAD OF 触发器,因此它会在 INSERT、UPDATE 或 DELETE 语句执行之前执行。它还使用了 FOR EACH ROW 子句,以便在每行上执行相应的操作。 在触发器的主体内部,我们使用了 IF-ELSIF 结构来确定正在执行的操作类型,并相应地插入、更新或删除日志信息以及 `employees` 中的记录。 这就是一个简单的 Oracle PL/SQL INSTEAD OF 触发器示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值