Desambiguación de restricciones/columnas de clave externa
Suponiendo que se está refiriendo a las restricciones de clave externa , la respuesta corta sería simplemente no los usas .
Y aquí viene el largo:
Estamos acostumbrados a referirnos a columnas como claves externas a otras mesas. Especialmente durante el proceso de normalización, frases como "user_purchase.i_id
es una clave foránea para los items
mesa" sería muy común. Si bien esa es una forma perfectamente válida de describir la relación, puede volverse un poco confuso cuando lleguemos a la fase de implementación.
Suponga que ha creado sus tablas sin la FOREIGN KEY
cláusulas:
CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
);
Observe que, en cuanto a la relación, las columnas de la clave foránea están todavía implementados . Hay una columna que hace referencia al user
tabla (id
) y otro que hace referencia a los items
tabla (i_id
) -- pongamos el name
columna a un lado por un momento. Considere los siguientes datos:
user user_purchase items
| id username | | id i_id | | i_id name price |
| 23 john | | 55 10 | | 10 chocolate bar 3.42 |
| 55 mary | | 70 10 | | 33 mobile phone 82.11 |
| 70 fred | | 70 33 | | 54 toothpaste 8.67 |
| 55 10 | | 26 toy car 6.00 |
| 70 26 |
La relación está ahí. Se implementa mediante el user_purchase
tabla, que contiene información sobre quién compró qué . Si tuviéramos que consultar la base de datos para un informe relevante, haríamos:
select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
Y así es como usamos la relación y las columnas de clave externa involucrado.
Ahora, ¿qué pasa si hacemos:
insert into user_purchase (id,i_id) values (23,99)
Aparentemente, esta es una entrada inválida. Aunque hay un usuario con id=23
, no hay ningún elemento con i_id=99
. El RDBMS permitiría que eso sucediera, porque no sabe nada mejor . Aún.
Ahí es donde la clave externa restricciones ven a jugar. Especificando FOREIGN KEY (i_id) REFERENCES items(i_id)
en el user_purchase
definición de la tabla, esencialmente le damos al RDBMS una regla a seguir:entradas con i_id
valores que no están contenidos en items.i_id
columna no son aceptables . En otras palabras, mientras una clave externa columna implementa la referencia , una clave foránea restricción hace cumplir la integridad referencial .
Tenga en cuenta, sin embargo, que el select
anterior no cambiaría, solo porque definió una restricción FK. Por lo tanto, usted no use restricciones FK, RDBMS sí, para proteger sus datos.
Redundancias
Pregúntate:¿Por qué querrías eso? Si las dos claves foráneas tienen el mismo propósito, la redundancia eventualmente lo meterá en problemas. Considere los siguientes datos:
user_purchase items
| id i_id name | | i_id name price |
| 55 10 chocolate bar | | 10 chocolate bar 3.42 |
| 70 10 chocolate bar | | 33 mobile phone 82.11 |
| 70 33 mobile phone | | 54 toothpaste 8.67 |
| 55 10 toothpaste | | 26 toy car 6.00 |
| 70 26 toy car |
Qué está mal con esta imagen? ¿El usuario 55
comprar dos barras de chocolate, o una barra de chocolate y una pasta de dientes? Este tipo de ambigüedad puede generar un gran esfuerzo para mantener los datos sincronizados, lo que sería innecesario si solo mantuviéramos una de las claves externas. De hecho, ¿por qué no soltar el name
columna por completo, ya que está implícito en la relación.
Por supuesto, podríamos resolver esto implementando una clave foránea compuesta, configurando PRIMARY KEY(i_id,name)
para los items
tabla (o definiendo un UNIQUE(i_id,name)
adicional index, en realidad no importa) y luego establecer una FOREIGN KEY(i_id,name) REFERENCES items(i_id,name)
. De esta forma, solo (i_id,name) parejas que existen en los items
la tabla sería válida para user_purchases
. Aparte del hecho de que todavía tendrías uno clave foránea , este enfoque es totalmente innecesario, siempre que el i_id
columna ya es suficiente para identificar un elemento (no puedo decir lo mismo para el name
columna...).
Sin embargo, no existe una regla contra el uso de múltiples claves externas en una tabla. De hecho, hay circunstancias que exigen tal enfoque. Considere una person(id,name)
tabla y un parent(person,father,mother)
uno, con los siguientes datos:
person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
Obviamente, las tres columnas del parent
table son claves foráneas para person
. No para la misma relación , sin embargo, pero para tres diferentes :Dado que los padres de una persona también son personas, las dos columnas correspondientes deben hacer referencia a la misma tabla person
hace. Tenga en cuenta, sin embargo, que los tres campos no solo pueden pero también tener que referir a otra person
s en el mismo parent
fila, ya que nadie es su propio padre y el padre de nadie es su madre también.