2010-04-23 8 views
5

¿Cuál es una buena manera de evitar que una tabla con 2 columnas, una (única) yb, tenga un registro donde la columna b sea igual a cualquier valor en la columna a? Esto se usaría para una tabla de correcciones de este tipo,¿Cómo evitar que la columna b contenga el mismo valor que cualquier columna a en Oracle?

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

puedo ver cómo se podría hacer con un gatillo y una sub consulta suponiendo que no hay actividad simultánea, pero un enfoque más declarativo sería preferible.

Este es un ejemplo de lo que debe ser evitado,

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

Lo ideal sería que la solución sería trabajar con inserciones concurrentes y actualizaciones.

+0

¿Está previsto que la columna A sea única en la tabla? – dpbradley

+0

Sí, la columna A debe tener la exclusividad aplicada. –

Respuesta

2

Puede usar una vista materializada para hacer cumplir sus requisitos (probado con 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 

El índice único se asegurará de que no pueda tener el mismo valor en ambas columnas (en dos filas).

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) 

Será serializar durante cometer pero sólo en los valores de las columnas A y B (es decir: en general no debe impedir la actividad disjuntos concurrente).

La unicidad solo se comprobará a la hora COMPROMISO y algunas herramientas no esperan que la confirmación falle y puede que se comporte de forma inapropiada. Además, cuando COMMIT falla, la transacción completa se revierte y usted pierde los cambios sin compromiso (no puede "volver a intentar").

+0

Me gusta esta solución porque lleva la responsabilidad de la integridad a un índice. –

0

Considere la posibilidad de una sesión Una inserción ('A', 'B') pero no comprometer, luego la sesión B inserta ('B', 'A') sin comprometer. Ninguna sesión puede ver el registro insertado por el otro. Entonces las sesiones se comprometen.

Puede serializar, bloqueando toda la tabla cuando se inserta una sesión (ANTES del desencadenador INSERT) y realice la comprobación en un desencadenante DESPUÉS DE INSERTAR. Si la tabla tiene el contenido que usted indica, no debería ver mucha actividad, por lo que la serialización no sería un problema.

Cuestiones relacionadas