Tengo una tabla como la siguiente:
create table my_table (
id int8 not null,
id_A int8 not null,
id_B int8 not null,
id_C int8 null,
constraint pk_my_table primary key (id),
constraint u_constrainte unique (id_A, id_B, id_C)
);
Y quiero (id_A, id_B, id_C)
ser distinto en cualquier situación. Por lo tanto, las siguientes dos inserciones deben provocar un error:
INSERT INTO my_table VALUES (1, 1, 2, NULL);
INSERT INTO my_table VALUES (2, 1, 2, NULL);
Pero no se comporta como se esperaba porque, según la documentación, dos NULL
valores no se comparan entre sí, por lo que ambas inserciones pasan sin error.
¿Cómo puedo garantizar mi restricción única, incluso si id_C
puede ser NULL
en este caso? En realidad, la verdadera pregunta es: ¿puedo garantizar este tipo de singularidad en "sql puro" o tengo que implementarlo en un nivel superior (Java en mi caso)?
postgresql
constraint
null
unique-constraint
Manuel Leduc
fuente
fuente
(1,2,1)
y(1,2,2)
en las(A,B,C)
columnas. ¿Debería(1,2,NULL)
permitirse que se agregue o no?Respuestas:
Puedes hacerlo en SQL puro . Cree un índice único parcial además del que tiene:
De esta manera puede ingresar
(a, b, c)
en su tabla:Pero ninguno de estos por segunda vez.
O use dos
UNIQUE
índices parciales y ningún índice completo (o restricción). La mejor solución depende de los detalles de sus requisitos. Comparar:Si bien esto es elegante y eficiente para una sola columna anulable en el
UNIQUE
índice, se descontrola rápidamente por más. Discutiendo esto, y cómo usar UPSERT con índices parciales:Aparte
No se pueden usar identificadores de mayúsculas y minúsculas sin comillas dobles en PostgreSQL.
Usted puede considerar una
serial
columna como clave principal o unaIDENTITY
columna en Postgres 10 o posterior. Relacionado:Entonces:
Si no espera más de 2 mil millones de filas (> 2147483647) durante la vida útil de su tabla (incluidos los desperdicios y las filas eliminadas), considere
integer
(4 bytes) en lugar debigint
(8 bytes).fuente
Tuve el mismo problema y encontré otra forma de tener un NULL único en la tabla.
En mi caso, el campo
foreign_key_field
es un entero positivo y nunca será -1.Entonces, para responder al Manual Leduc, otra solución podría ser
Supongo que los identificadores no serán -1.
¿Cuál es la ventaja de crear un índice parcial?
En caso de que no tenga la cláusula NOT NULL
id_a
,id_b
yid_c
pueda estar NULL juntos solo una vez.Con un índice parcial, los 3 campos podrían ser NULL más de una vez.
fuente
COALESCE
puede ser eficaz para restringir los duplicados, pero el índice no sería muy útil en las consultas, ya que es un índice de expresión que probablemente no coincida con las expresiones de consulta. Es decir, a menos que no estésSELECT COALESCE(col, -1) ...
golpeando el índice.Un nulo puede significar que el valor no se conoce para esa fila en este momento, pero se agregará, cuando se conozca, en el futuro (ejemplo
FinishDate
para una carreraProject
) o que no se puede aplicar ningún valor para esa fila (ejemploEscapeVelocity
para un agujero negroStar
).En mi opinión, generalmente es mejor normalizar las tablas eliminando todos los Nulos.
En su caso, desea permitir
NULLs
en su columna, pero desea que solo seNULL
permita uno . ¿Por qué? ¿Qué tipo de relación es esta entre las dos tablas?Quizás pueda simplemente cambiar la columna
NOT NULL
y almacenar, en lugar deNULL
, un valor especial (como-1
) que se sabe que nunca aparece. Esto resolverá el problema de restricción de unicidad (pero puede tener otros efectos secundarios posiblemente no deseados. Por ejemplo, usar-1
para significar "no conocido / no se aplica" sesgará cualquier cálculo de suma o promedio en la columna. O todos esos cálculos tendrán que tomarse tener en cuenta el valor especial e ignorarlo.)fuente