oracle Deferrable constraint 详解以及用法.

本文深入探讨了Oracle数据库中约束验证时机的两种类型:即时验证和延时验证。通过实例展示了每种类型的具体应用和区别,帮助读者理解如何在不同场景下灵活运用这些验证机制。

1. 两种验证时机.

Oracle的constraints(约束) 根据验证时机可以分成两种.


case 1.  在每一句insert statement 执行时就会马上验证, 如果约束验证失败,  则这句sql statement 会执行失败.

case 2.   执行insert statements 时不会验证,   在commit的时候验证, 如果验证失败, 则整个Transaction 回滚.




2.constraints的分类

对应地,  oracle 的 constraints 也可以分成两大类.

一种是not deferrable (不可以延时的) . 这种情况下只能执行 case1 的验证时机(即时验证)

另一种是 defferable (可以设置成延时的).   这种情况下可以执行 case 1 或 case2 的验证时机. 但需要设置.


对于第二种defferable 分类, 还可以分成两小类.

一种是 initially immediate ,  意思时默认情况下执行case 1.

另一种是initially deferred,  意思是默认情况下执行case2.


也就是可以分成三种


1. not deferrable

2. deferrable   initially immediate

3. deferrable   initially deferred.


如下图:




下面会举一些例子来详细解释这个3种 constraints的区别:


2.1 not deferrable constraints

这种最常见也最简单.  如果在增加1个constraint 时不指定验证时机属性. 默认情况下就会被设为not deferrable.

既然constraint 是不可以延时验证的,  所以也不用设定它的初始属性(实际上就是initially immediate)


例子:

首先我们建立1张空表:

create table T1 (id number(10,0),
                   nm varchar(10));


接下来为id列 增加1个唯一约束t1_id:

SQL> alter table T1 add constraint t1_id  unique(id);

Table altered.

注意这时并没有指定 Deferrable 属性, 所以默认情况下就是 not deferrable 的. 我们可以通过user_constraints视图来检查它的属性:


SQL> select table_name, constraint_name, status, deferrable, deferred, validated from user_constraints where table_name = 'T1';

TABLE_NAME CONSTRAINT_NAME STATUS   DEFERRABLE	   DEFERRED  VALIDATED
---------- --------------- -------- -------------- --------- -------------
T1	   T1_ID	   ENABLED  NOT DEFERRABLE IMMEDIATE VALIDATED

注意Deferrable 属性是 not deferrable.   而 Deferred 属性(Initially 初始属性) 是immediate.


这时我们连续执行3句insert sql:

SQL> insert into T1 values(1, 'abc1');

1 row created.

SQL> insert into T1 values(2, 'abc2');

1 row created.

SQL> insert into T1 values(2, 'abc3');
insert into T1 values(2, 'abc3')
*
ERROR at line 1:
ORA-00001: unique constraint (BILL.T1_ID) violated

可以见到第一第二句insert statement 能正常执行,  但第三句执行失败, 因为id=2 与第二句重复了, 约束验证失败. 

所以说验证时机属于case1, 即时验证.

这种验证时机也是最常见的.



2.2 deferrable initially immediate constraints

这种约束默认情况下等于第一种约束(not deferrable), 但是它可以在事务中改变设置, 变成延时验证的约束.


我们可以这样理解.  

第一个属性deferrable 表示 这个约束可以被设置成延时验证.

第二个属性initially immediate 表示这个约束默认情况下是即时验证.


我们继续利用上面的例子.

首先, 清空上面那个例子表.  由于上面操作没有提交, 所以回滚就ok了.

SQL> rollback;

Rollback complete.


然后我们修改(删除再建立)那个约束, 射程deferrable initiallly immediate 模式.

SQL> alter table T1 drop constraint t1_id;

Table altered.

SQL> alter table T1 add constraint t1_id unique(id) initially immediate deferrable ;

Table altered.

SQL> 


这时我们去user_constraints视图检查属性:

SQL> select table_name, constraint_name, status, deferrable, deferred, validated from user_constraints where table_name = 'T1';

TABLE_NAME CONSTRAINT_NAME STATUS   DEFERRABLE	   DEFERRED  VALIDATED
---------- --------------- -------- -------------- --------- -------------
T1	   T1_ID	   ENABLED  DEFERRABLE	   IMMEDIATE VALIDATED

可以见到只有1个属性与Not Defferable constraint有区别,  就是 deferrable  属性是 deferrable了.   但是 deferred (初始属性) 还是 immediate.



我们继续尝试插入上面的三行数据:

SQL> insert into T1 values(1, 'abc1');

1 row created.

SQL> insert into T1 values(2, 'abc2');

1 row created.

SQL> insert into T1 values(2, 'abc3');
insert into T1 values(2, 'abc3')
*
ERROR at line 1:
ORA-00001: unique constraint (BILL.T1_ID) violated

可以到执行结果与上面一模一样. 没有区别. 也就是说也是case 1模式.


我们检索这张表, 只有两行数据, 然后回滚, 那么就清空这张表了.

SQL> select * from T1;

	ID NM
---------- ----------
	 1 abc1
	 2 abc2

SQL> rollback;

Rollback complete.

SQL> select * from T1;

no rows selected

SQL> 


好了, 现在就是重点了, deferrable可以在事务中临时改变成另1种模式.

也就是说可以由case1 临时设置为 case 2.

syntax:

set constraint  <constraint_name>  deferred/immediate


注意上面的语句并没有改变这个constraint的任何属性, 只不过是切换为另一种模式

也就是说初始是immediate模式的,   执行上面的语句后就临时变成deferred模式了.


我们接回上面的例子, 执行另一只模式:

SQL> set constraint t1_id deferred;

Constraint set.

我们查下这个constraint的属性, 发现属性完全无改变,  Deferred属性还是immediate.  因为Deferred这个属性指的是初始属性.


SQL> select table_name, constraint_name, status, deferrable, deferred, validated from user_constraints where table_name = 'T1';

TABLE_NAME CONSTRAINT_NAME STATUS   DEFERRABLE	   DEFERRED  VALIDATED
---------- --------------- -------- -------------- --------- -------------
T1	   T1_ID	   ENABLED  DEFERRABLE	   IMMEDIATE VALIDATED



这时我们insert上面的三条记录.  发现3条insert都可以被插入到数据表中.

SQL> insert into T1 values(1, 'abc1');

1 row created.

SQL> insert into T1 values(2, 'abc2');

1 row created.

SQL> insert into T1 values(2, 'abc3');

1 row created.

SQL> select * from T1;

	ID NM
---------- ----------
	 1 abc1
	 2 abc2
	 2 abc3

SQL> 


则说明这时在insert 语句执行时不会执行这个约束的验证, 三行都被插入到表中了,  但是在提交时回验证.

SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-00001: unique constraint (BILL.T1_ID) violated


见到提交失败, 而且整个事务会回滚,  也就是说这时表里面连第一第二句的insert记录也没有了.

SQL> select * from T1;

no rows selected


这个跟not defferable constraint有区别啊,  那种在每一句sql statement执行验证, 而且验证失败时并不会回滚事务.



好了下面也是重点:

当我们commit失败后被回滚,  也就是代表当前的事务结束了. 

而上面我们提到过, 使用 set constraint 语句 切换constraint到另一种模式只会在当前事务中生效.

也就是指, 事务结束后, 这个constraint就会返回初始模式!


我们再尝试插入三条语句:

SQL> insert into T1 values(1, 'abc1');

1 row created.

SQL> insert into T1 values(2, 'abc2');

1 row created.

SQL> insert into T1 values(2, 'abc3');
insert into T1 values(2, 'abc3')
*
ERROR at line 1:
ORA-00001: unique constraint (BILL.T1_ID) violated

发现再次在第三句执行时被执行即时验证, 因为在新事务中,  constraint t1_id又切换回 immediate 模式了.


2.3 deferrable initially deferred constraints

如果理解了第二种constraint, 那么最后一种就很简单了


第一个属性deferrable 表示 这个约束可以被设置成延时验证.

第二个属性initially immediate 表示这个约束默认情况下是延时验证.


但是可以用set constraint语句 在1个事务中临时切换为 即时验证.







<think>嗯,用户现在想查找Oracle数据库中与约束相关的系统视图或元数据信息。首先,我需要确定用户的需求是什么。可能他们需要了解有哪些系统视图可以用来查询约束的信息,比如约束类型、所属表、列名、状态等等。 首先,我应该回忆Oracle的系统视图。比如,DBA_CONSTRAINTS、ALL_CONSTRAINTS和USER_CONSTRAINTS这几个视图是常用的,分别对应不同权限下的约束信息。这些视图包含了约束的名称、类型、所属表、状态等基本信息。然后,约束可能涉及列,所以相关的还有DBA_CONS_COLUMNS、ALL_CONS_COLUMNS和USER_CONS_COLUMNS,这些视图可以显示约束涉及的列。 接下来,用户可能需要知道如何查询这些信息。例如,查询某个表的所有主键约束,或者外键约束。这时候需要结合DBA_CONSTRAINTS和DBA_CONS_COLUMNS,通过约束名关联起来。例如,用JOIN ON CONSTRAINT_NAME来获取列的具体信息。 另外,约束类型可能有不同的代码,比如'P'代表主键,'R'是外键,'U'是唯一约束,'C'是检查约束。这些代码需要解释清楚,方便用户理解查询结果。 还有可能用户需要了解约束的状态,是否启用,是否是延迟约束等等。DBA_CONSTRAINTS中的STATUS字段可以显示ENABLED或DISABLED,DEFERRABLE字段说明是否可延迟。 另外,可能用户需要知道如何生成启用或禁用约束的DDL语句,这时候可能需要访问DBA_CONSTRAINTS中的信息,结合DBMS_METADATA包来生成脚本。 还要注意权限问题。DBA视图需要DBA权限,而普通用户可能只能访问ALL或USER视图。需要提醒用户根据自身权限选择合适的视图。 用户可能在实际使用中遇到问题,比如如何查找外键引用的表和列,这时候需要关联DBA_CONSTRAINTS的R_CONSTRAINT_NAME到另一个约束,再通过DBA_CONS_COLUMNS获取列信息。 最后,可能需要给出示例查询,帮助用户更好地理解如何使用这些视图。例如,查询某个表的所有约束及其类型和状态,或者列出所有外键及其关联的表和列。 总结一下,回答应该包括主要的系统视图、各视图的列含义,如何联合查询获取详细信息,约束类型的解释,以及示例SQL语句。同时提醒用户权限问题和相关元数据的使用方法。</think>### Oracle约束相关系统视图与元数据 在Oracle数据库中,约束信息存储在系统提供的**数据字典视图**中。以下是常用的约束相关视图及其使用方法: --- #### 1. 核心约束视图 **1.1 DBA/ALL/USER_CONSTRAINTS** 存储所有约束的定义信息,包括主键、外键、唯一键、检查约束等: ```sql SELECT constraint_name, constraint_type, table_name, status, deferrable FROM dba_constraints WHERE owner = 'SCHEMA_NAME'; -- 替换为实际模式名 ``` - **`constraint_type`** 字段含义: - `P`: 主键 (PRIMARY KEY) - `R`: 外键 (FOREIGN KEY) - `U`: 唯一约束 (UNIQUE) - `C`: 检查约束 (CHECK) - `O`: 引用只读表时的约束 **1.2 DBA/ALL/USER_CONS_COLUMNS** 记录约束涉及的列信息: ```sql SELECT column_name, position FROM dba_cons_columns WHERE constraint_name = 'CONSTRAINT_NAME'; -- 替换为实际约束名 ``` --- #### 2. 高级元数据查询 **2.1 查询外键引用关系** 通过关联约束视图获取外键依赖: ```sql SELECT a.table_name, a.constraint_name, b.table_name AS referenced_table, c.column_name AS referenced_column FROM dba_constraints a JOIN dba_constraints b ON a.r_constraint_name = b.constraint_name JOIN dba_cons_columns c ON b.constraint_name = c.constraint_name WHERE a.constraint_type = 'R'; ``` **2.2 检查约束的表达式** 查看检查约束的详细条件: ```sql SELECT search_condition FROM dba_constraints WHERE constraint_type = 'C' AND constraint_name = 'CHECK_CONSTRAINT_NAME'; ``` --- #### 3. 元数据工具函数 使用 **`DBMS_METADATA`** 生成约束DDL: ```sql SELECT DBMS_METADATA.GET_DDL('CONSTRAINT', 'CONSTRAINT_NAME', 'SCHEMA_NAME') FROM dual; ``` --- #### 4. 约束状态管理 **4.1 查看约束启用状态** ```sql SELECT constraint_name, status FROM dba_constraints WHERE status = 'DISABLED'; -- 查找禁用状态的约束 ``` **4.2 延迟约束检查** 通过 **`DEFERRABLE`** 字段判断是否支持延迟验证: ```sql SELECT constraint_name, deferrable, deferred FROM dba_constraints WHERE deferrable = 'DEFERRABLE'; ``` --- #### 引用说明 Oracle数据字典视图通过`SYS`模式存储所有对象的元数据[^1]。对于非DBA用户,建议使用`ALL_`或`USER_`前缀的视图(如`USER_CONSTRAINTS`)以避免权限问题。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nvd11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值