常见问题--表的约束initially immediate 理解

本文深入探讨了Oracle数据库中约束的两种执行方式:初始化立即执行与初始化延迟执行。通过实例展示了这两种方式如何影响数据插入操作及事务提交过程。此外,还讨论了延迟执行约束的实际应用场景。

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

初始化立即执行--在每条语句执行结束时检验约束 

初始化延迟执行--一直等到事务完成后(或者调用set constraint immediate语句时)才检验约束 

来看下面的代码:

SQL> create table t

2 ( x int constraint 
check_x check ( x > 0 ) 
deferrable 
initially immediate,
3 y int constraint 
check_y check ( y > 0 ) 
deferrable 
initially deferred
4 )
5 /
Table created.

SQL> insert into t values ( 1,1 );
1 row created.

SQL> commit;
Commit complete.

所以,当两个约束同时满足时才能正确无误地插入行。但是,如果我试图插入违反CHECK_X约束(初始化立即执行的约束)的行,则系统会立即检验约束,并得到下面的结果:

SQL> insert into t values ( -1,1);

insert into t values ( -1,1)
*
ERROR at line 1:
ORA-02290: check constraint 
(OPS$TKYTE.CHECK_X) violated

由于CHECK_X是可延迟但初始化为立即执行的约束,所以这一行立刻被拒绝了。而CHECK_Y则不同,它不仅是可延迟的,而且初始化为延迟执行,这就意味着直到我用COMMIT命令提交事务或将约束状态设置为立即执行时才检验约束。 

SQL> insert into t values ( 1,-1);
1 row created. 

现在它是成功的(总之到目前为止是成功的)。我将约束检验延迟到了执行COMMIT的时候: 

SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02290: check constraint 
(OPS$TKYTE.CHECK_Y) violated

此时数据库将事务回滚,因为违反约束导致了COMMIT语句的失败。这些语句说明了初始化立即执行与初始化延迟执行约束之间的区别。initially(初始化)部分指定Oracle什么时候会进行默认的约束检验--是在语句结束时[immediate(立即执行)],还是在事务结束时[deferred(延迟执行)]。我还要说明deferred(可延迟)子句有什么用。我可以发出命令,让所有可延迟的约束变为延迟执行的。注意,你也可以对一个约束使用该命令;你不必让所有可延迟的约束都变为延迟执行的:

SQL> set constraints all deferred;
Constraint set.

SQL> insert into t values ( -1,1);
1 row created. 

由于将初始化立即执行的约束设置为延迟执行的模式,这个语句似乎执行成功;但是,当我用COMMIT语句提交事务时,看一下会发生什么: 

SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02290: check constraint 
(OPS$TKYTE.CHECK_X) violated 

事务提交失败并回滚,因为在COMMIT语句之后对约束进行了检验。相反,我可以将初始化为延迟执行的约束变为"立即"执行的约束: 

SQL> set constraints all immediate;
Constraint set.

SQL> insert into t values ( 1,-1);
insert into t values ( 1,-1)
*
ERROR at line 1:
ORA-02290: check constraint 
(OPS$TKYTE.CHECK_Y) violated 

前面在我提交前能执行的语句现在立即出了问题。因为我手动修改了默认的约束模式。

延迟约束有哪些实际用处呢? 有很多。它主要用于物化视图(快照)。这些视图会使用延迟约束来进行视图刷新。在刷新物化视图的过程中,可能会破坏完整性,而且将不能逐句检验约束。但到执行COMMIT时,数据完整性就没问题了,而且能满足约束。没有延迟约束,物化视图的约束可能会使刷新过程不能成功进行。

使用延迟约束的另一个普遍原因是,当预测是否需要更新父/子关系中的主键时,它有助于级联更新。如果你将外键设为可延迟、但初始化为立即执行,那么你就可以将所有约束设置为可延迟。 

将父键更新为一个新值--至此子关系的完整性约束不会被验证。将子外键更新为这个新值。 COMMIT--只要所有受更新影响的子记录都指向现有的父记录,这条命令就能成功执行。

转:http://www.host01.com/article/database/00060004/0542413042257005.htm

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15720542/viewspace-622173/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/15720542/viewspace-622173/

### 关于达梦数据库 DM8 中默认约束 `DEFAULT` 表 `STAT` 无效 (错误码 2670) 的解决方案 在达梦数据库 DM8 中,当遇到表的默认约束无效问题(错误码 2670),通常是因为定义的默认值不符合字段的数据类型或长度限制。以下是针对该问题的具体分析与解决方法: #### 1. **确认字段定义** 需要先检查表结构中涉及 `STAT` 字段的相关定义是否合理。可以通过以下 SQL 查询获取表结构信息: ```sql SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMN_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME = 'YOUR_TABLE_NAME'; ``` 如果查询结果显示 `COLUMN_DEFAULT` 值不匹配字段的实际需求,则可能是导致错误的原因之一[^1]。 #### 2. **验证默认值合法性** 达梦数据库对于默认值有严格的校验机制。如果设置的默认值超出了字段范围或者违反了其他约束条件,就会触发错误码 2670。例如,假设 `STAT` 是一个字符型字段 (`VARCHAR2`) 并设置了固定长度为 1,而默认值却是一个超过此长度的字符串,则会报错。 修改默认值使其满足字段要求可以解决问题。例如: ```sql ALTER TABLE YOUR_TABLE MODIFY STAT VARCHAR2(1) DEFAULT 'Y'; -- 确保默认值符合字段长度 ``` #### 3. **重新创建约束** 若发现现有默认约束确实存在问题,可以选择删除原有约束并重建新的合法约束。操作步骤如下: - 删除旧的默认约束: ```sql ALTER TABLE YOUR_TABLE DROP CONSTRAINT constraint_name; ``` - 添加新的默认约束: ```sql ALTER TABLE YOUR_TABLE ADD CONSTRAINT default_stat CHECK (STAT IN ('Y', 'N')) INITIALLY IMMEDIATE DEFERRABLE; ``` #### 4. **测试修改后的效果** 完成上述调整之后,建议通过插入新记录来检验修复情况: ```sql INSERT INTO YOUR_TABLE (ID, NAME, STAT) VALUES (1, 'TestName', NULL); -- 测试默认值生效与否 SELECT * FROM YOUR_TABLE WHERE ID = 1; ``` #### 5. **注意事项** 在实际应用过程中还需注意以下几点事项以避免类似问题再次发生: - 明确各列数据类型的边界条件; - 对新增加的字段谨慎设定初始状态; - 使用工具如 DISQL 进行调试前需按照指定格式连接至目标实例[^3]。 ```python def validate_default_value(field_type, proposed_default): """Validate whether the given default value matches field type.""" valid_map = { "NUMBER": lambda x: isinstance(x, int), "DATE": lambda x: isinstance(x, str) and re.match(r"\d{4}-\d{2}-\d{2}", x), "VARCHAR2": lambda x: isinstance(x, str) and len(x.strip()) <= max_length, } validation_func = valid_map.get(field_type.upper()) if not validation_func or not validation_func(proposed_default): raise ValueError(f"Default value {proposed_default} does not match expected format for {field_type}.") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值