Aquí hay un pequeño experimento que ejecuté en una base de datos Oracle (10g). Aparte de la conveniencia de la implementación de (Oracle), no puedo entender por qué algunas inserciones son aceptadas y otras rechazadas.¿Cómo puedo restringir varias columnas para evitar duplicados, pero ignorar los valores nulos?
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
Asumiendo que tiene sentido tener ocasionalmente algunas filas con valores desconocidos alguna columna, puedo pensar en dos posibles casos de uso relacionados con la prevención de duplicados:
1. Quiero rechazar duplicados, pero aceptar cuando cualquier restringido el valor de la columna es desconocido.
2. Deseo rechazar los duplicados, incluso en los casos en que se desconoce el valor de una columna restringida.
Al parecer Oracle implementa algo diferente, sin embargo:
3. Rechazar duplicados, pero aceptan (sólo) cuando todos los valores de las columnas restringidos son desconocidos.
Puedo pensar en maneras de utilizar la implementación de Oracle para llegar al caso de uso (2), por ejemplo, tener un valor especial para "desconocido" y hacer que las columnas no sean nulas. Pero no puedo entender cómo usar el caso (1).
En otras palabras, ¿cómo puedo conseguir que Oracle actúe así?
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
ejemplo perfecto de una buena pregunta (y además es uno respondí que necesitaba!) – orbfish