5

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

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

我可以看到如何在没有并发活动的情况下使用触发器和子查询来完成它,但更可取的是更具声明性的方法。

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

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

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

4

2 回答 2

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 时检查,并且某些工具不会期望提交失败并且可能会出现不恰当的行为。此外,当 COMMIT 失败时,整个事务都会回滚,并且您会丢失任何未提交的更改(您不能“重试”)。

于 2010-04-24T09:54:48.173 回答
0

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

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

于 2010-04-24T00:38:37.733 回答