如何防止列b包含与Oracle中任何列a相同的值?

时间:2010-04-23 15:56:07

标签: oracle data-integrity

防止具有2列的表(a(唯一)和b)有哪些记录,其中列b等于列a中的任何值,有什么好方法?这将用于这样的更正表,

MR   -> Mr
Prf. -> Prof.
MRs  -> Mrs

我可以看到如何使用触发器和子查询来完成,假设没有并发活动,但更多的声明性方法更可取。

这是应该防止的一个例子,

Wing Commdr. -> Wing Cdr.
Wing Cdr.    -> Wing Commander

理想情况下,该解决方案适用于并发插入和更新。

2 个答案:

答案 0 :(得分:2)

您可以使用物化视图来强制执行您的要求(使用10.2.0.1进行测试)。

SQL> CREATE TABLE t (a VARCHAR2(20) NOT NULL PRIMARY KEY,
  2                  b VARCHAR2(20) NOT NULL);
Table created

SQL> CREATE MATERIALIZED VIEW LOG ON t WITH (b), ROWID INCLUDING NEW VALUES;     
Materialized view log created

SQL> CREATE MATERIALIZED VIEW mv
  2     REFRESH FAST ON COMMIT
  3  AS
  4  SELECT 1 umarker, COUNT(*) c, count(a) cc, a val_col
  5    FROM t
  6   GROUP BY a
  7  UNION ALL
  8  SELECT 2 umarker, COUNT(*), COUNT(b), b
  9    FROM t
 10    GROUP BY b;     
Materialized view created

SQL> CREATE UNIQUE INDEX idx ON mv (val_col);     
Index created 

唯一索引将确保两列中的值不能相同(在两行上)。

SQL> INSERT INTO t VALUES ('Wing Commdr.', 'Wing Cdr.');     
1 row inserted

SQL> COMMIT;     
Commit complete

SQL> INSERT INTO t VALUES ('Wing Cdr.', 'Wing Commander');     
1 row inserted

SQL> COMMIT;     

ORA-12008: erreur dans le chemin de régénération de la vue matérialisée
ORA-00001: violation de contrainte unique (VNZ.IDX)

SQL> INSERT INTO t VALUES ('X', 'Wing Commdr.');     
1 row inserted

SQL> COMMIT;

ORA-12008: erreur dans le chemin de régénération de la vue matérialisée
ORA-00001: violation de contrainte unique (VNZ.IDX)

它将在提交期间序列化,但仅限于列A和B的值(即:通常它不应该阻止并发的不相交活动)。

只会在COMMIT时检查unicity,并且某些工具不会指望提交失败并且可能表现不当。此外,当COMMIT失败时,整个事务将回滚,您将丢失所有未经修改的更改(您无法“重试”)。

答案 1 :(得分:0)

考虑会话A插入('A','B')但不提交,然后会话B插入('B','A')而不提交。两个会话都不能看到另一个会话插入的记录。然后会话提交。

您可以通过在一个会话插入(BEFORE INSERT触发器)时锁定整个表来序列化,并在AFTER INSERT触发器中执行检查。如果表中包含您指定的内容,则不应该看到很多活动,因此序列化不会成为问题。