¿Por qué las claves foráneas compuestas necesitan una restricción única separada?

10

Aquí hay una tabla simple donde los registros pueden hacer referencia a registros primarios en la misma tabla:

CREATE TABLE foo (
    id         SERIAL  PRIMARY KEY,
    parent_id  INT     NULL,
    num        INT     NOT NULL,
    txt        TEXT    NULL,
    FOREIGN KEY (parent_id) REFERENCES foo(id)
);

Con el requisito adicional de que uno de los otros valores de campo ( num) debe ser idéntico entre los registros primarios y secundarios, pensé que una clave externa compuesta debería ser la solución. Cambié la última línea a

    FOREIGN KEY (parent_id, num) REFERENCES foo(id, num)

y obtuve ERROR: no existe una restricción única que coincida con las claves dadas para la tabla referenciada "foo" .

Puedo agregar fácilmente esta restricción, pero no entiendo por qué es necesaria, cuando una de las columnas a las que se hace referencia ( id) ya se garantiza que es única. A mi modo de ver, la nueva restricción sería redundante.

Zilk
fuente

Respuestas:

11

Es una limitación del DBMS, en todos ellos, que yo sepa. Y no solo al agregar una columna, sino también al reorganizar columnas. Si tenemos una UNIQUErestricción (a1, a2), no podemos agregar FOREIGN KEYeso a REFERENCES (a2, a1)menos que haya una restricción única sobre eso (a2, a1)que sea esencialmente redundante.

No sería terriblemente difícil agregar esto como una característica:

Cuando hay una UNIQUErestricción activada (a), cualquiera (a, b, c, ..., z)o (b,c, ...a, ...z)combinación también está garantizada UNIQUE.

o la generalización:

Cuando existe una UNIQUErestricción (a1, a2, ..., aN), (a1, a2, ..., aN, b1, b2, ..., bM)también se garantiza cualquier combinación o reordenamiento UNIQUE.

Parece que no se le ha preguntado o no se ha considerado con la prioridad suficiente para ser implementado.

Siempre puede hacer una solicitud, en el canal respectivo, para que se implemente la función. O incluso impleméntelo usted mismo, si el DBMS es de código abierto, como Postgres.

ypercubeᵀᴹ
fuente
No estoy seguro de que sea así de simple. ¿Qué pasa con los índices parciales o los valores NULL? etc. NULL podría funcionar bien si está satisfecho NULL != NULL. De todos modos .. :)
Joishi Bodio
@JoishiBodio No creo que los nulos sean un problema. Las restricciones ÚNICAS se pueden definir o columnas anulables también. El valor predeterminado es que si alguna columna tiene un valor NULL, se pasa la restricción y se acepta la fila.
ypercubeᵀᴹ
Sin embargo, en el segundo, si a1, a2, ... aN no son anulables y b1, b2, bM si tenemos problemas. Pero la característica seguramente podría implementarse para columnas no anulables. Lo que probablemente es preocupante son las implicaciones de eficiencia.
ypercubeᵀᴹ
Estoy familiarizado con UNIQUE INDEXdónde están las columnas NULLABLE... por eso lo mencioné. :) Pero estoy de acuerdo, en el caso de que no haya NULL (y tampoco un índice parcial), probablemente sea bastante sencillo.
Joishi Bodio
5

Las claves externas en general (no solo compuestas) DEBEN apuntar a una CLAVE ÚNICA de algún tipo en otra tabla. Si no lo hicieran, no habría integridad de datos relacionales.

Esto se queja porque, si bien tiene una clave única en (id) ... NO tiene una clave única en (id, num) ... Por lo tanto, en lo que respecta a la base de datos, el par (id, num) es No GARANTIZADO para ser único. Nosotros, como humanos, podemos descubrir que será único, pero estoy seguro de que tendrían que agregar una gran cantidad de código adicional para que Postgres sea lo suficientemente inteligente como para ver que "oh hey ... se supone que la identificación es única". , así que id, num también debe ser único "..

Me sorprendería mucho si agregaran ese código cuando todo lo que tiene que hacer es crear otro índice único en las dos columnas para solucionar el problema.

Para ser claros, el código que tendrían que agregar no sería solo este caso simple ... tendría que manejar todos los casos, incluso aquellos en los que la clave externa está en 4+ columnas, etc. Estoy seguro La lógica sería bastante compleja.

Joishi Bodio
fuente