Ecco un piccolo esperimento che ho eseguito in un database Oracle (10g). A prescindere dalla convenienza dell'implementazione (Oracle), non riesco a capire perché alcuni inserimenti siano accettati e altri rifiutati.Come posso vincolare più colonne per evitare duplicati, ma ignorare valori nulli?
create table sandbox(a number(10,0), b number(10,0));
create unique index sandbox_idx on sandbox(a,b);
insert into sandbox values (1,1); -- accepted
insert into sandbox values (1,2); -- accepted
insert into sandbox values (1,1); -- rejected
insert into sandbox values (1,null); -- accepted
insert into sandbox values (2,null); -- accepted
insert into sandbox values (1,null); -- rejected
insert into sandbox values (null,1); -- accepted
insert into sandbox values (null,2); -- accepted
insert into sandbox values (null,1); -- rejected
insert into sandbox values (null,null); -- accepted
insert into sandbox values (null,null); -- accepted
Supponendo che ha senso avere di tanto in tanto alcune righe con qualche colonna di valori ignoti, posso pensare a due possibili casi d'uso che coinvolgono i duplicati impedendo:
1. Voglio respingere i duplicati, ma accettare quando qualsiasi vincolata il valore della colonna è sconosciuto.
2. Voglio rifiutare i duplicati, anche nei casi in cui il valore di una colonna vincolata è sconosciuto.
Apparentemente Oracle implementa qualcosa di diverso però:
3. Rifiuta duplicati, ma accetta (solo) quando tutti valori delle colonne vincolate sono sconosciuti.
Sono in grado di pensare a come utilizzare l'implementazione di Oracle per utilizzare case (2), ad esempio, avere un valore speciale per "unknown" e rendere le colonne non annullabili. Ma non riesco a capire come usare il caso (1).
In altre parole, come posso convincere Oracle ad agire in questo modo?
create table sandbox(a number(10,0), b number(10,0));
create unique index sandbox_idx on sandbox(a,b);
insert into sandbox values (1,1); -- accepted
insert into sandbox values (1,2); -- accepted
insert into sandbox values (1,1); -- rejected
insert into sandbox values (1,null); -- accepted
insert into sandbox values (2,null); -- accepted
insert into sandbox values (1,null); -- accepted
insert into sandbox values (null,1); -- accepted
insert into sandbox values (null,2); -- accepted
insert into sandbox values (null,1); -- accepted
insert into sandbox values (null,null); -- accepted
insert into sandbox values (null,null); -- accepted
Perfetto esempio di una buona domanda (più è quello che ho bisogno di risposto!) – orbfish