2010-04-23 20 views
5

Che cosa è un buon modo per impedire a una tabella con 2 colonne, a (unica) eb, di avere un record in cui la colonna b è uguale a qualsiasi valore nella colonna a? Questo potrebbe essere utilizzato per una tabella di correzione come questo,Come impedire la colonna b che contiene lo stesso valore di qualsiasi colonna a in Oracle?

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

posso vedere come potrebbe essere fatto con un grilletto e un subquery supponendo attività simultanee ma un approccio più dichiarativo sarebbe preferibile.

Questo è un esempio di ciò che dovrebbe essere evitata,

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

Idealmente la soluzione potrebbe funzionare con inserti simultanee e aggiornamenti.

+0

È inteso che la colonna A sia unica nella tabella? – dpbradley

+0

Sì, la colonna A dovrebbe avere univocità applicata. –

risposta

2

È possibile utilizzare una vista materializzata per far rispettare i requisiti (testati 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 

L'indice univoco garantisce che non è possibile avere lo stesso valore in entrambe le colonne (su due righe).

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) 

Sarà serializzare durante commit ma solo sui valori delle colonne A e B (cioè: in generale non dovrebbe impedire attività disgiunto simultanee).

L'unicità verrà controllata solo al momento di COMMIT e alcuni strumenti non prevedono il fallimento del commit e potrebbero comportarsi in modo inappropriato. Inoltre, quando COMMIT fallisce, l'intera transazione viene ripristinata e si perdono tutte le modifiche non modificate (non è possibile "riprovare").

+0

Mi piace questa soluzione perché spinge la responsabilità per l'integrità in un indice. –

0

Prendere in considerazione la sessione A inserendo ('A', 'B') ma non commettendo, quindi la sessione B inserisce ('B', 'A') senza commit. Nessuna delle due sessioni può vedere il record inserito dall'altro. Quindi le sessioni si impegnano.

È possibile serializzare, bloccando l'intera tabella quando una sessione si inserisce (trigger BEFORE INSERT) e si esegue il check in un trigger AFTER INSERT. Se la tabella ha il contenuto che indichi, non dovrebbe vedere molta attività, quindi la serializzazione non sarebbe un problema.

Problemi correlati