Tengo una tabla donde las filas pueden estar relacionadas entre sí, y lógicamente, la relación va en ambos sentidos (básicamente, no tiene dirección) entre las dos filas. (Y si se está preguntando, sí, esto realmente debería ser una tabla. Son dos cosas de la misma entidad / tipo lógico). Puedo pensar en un par de formas de representar esto:
- Almacenar la relación y su reverso
- Almacene la relación de una manera, impida que la base de datos la almacene de la otra manera, y tenga dos índices con órdenes opuestas para las FK (un índice es el índice PK)
- Almacene la relación de una manera con dos índices y permita que se inserte el segundo de todos modos (suena un poco asqueroso, pero bueno, lo completo)
- Cree algún tipo de tabla de agrupación y tenga un FK en la tabla original. (Plantea muchas preguntas. La tabla de agrupación solo tendría un número; ¿por qué incluso tener la tabla? ¿Hacer FK NULLable o tener grupos con una sola fila asociada?)
¿Cuáles son algunas de las principales ventajas y desventajas de estas formas y, por supuesto, hay alguna forma en la que no haya pensado?
Aquí hay un SQLFiddle para jugar: http://sqlfiddle.com/#!12/7ee1a/1/0 . (Parece ser PostgreSQL ya que eso es lo que estoy usando, pero no creo que esta pregunta sea muy específica para PostgreSQL). Actualmente almacena la relación y su reversa solo como un ejemplo.
database-design
foreign-key
jpmc26
fuente
fuente
Respuestas:
Lo que has diseñado es bueno. Lo que hay que agregar es una restricción para que la relación no tenga dirección. Por lo tanto, no puede tener una
(1,5)
fila sin que(5,1)
se agregue una fila también.Esto se puede lograr * con una restricción de autorreferencia en la tabla del puente.
*: se puede lograr en Postgres, Oracle, DB2 y todos los DBMS que han implementado restricciones de clave externa como lo describe el estándar SQL (diferido, por ejemplo, verificado al final de la transacción). La verificación diferida no es realmente necesaria de todos modos, como en SQL- Servidor que los verifica al final del extracto y esta construcción aún funciona. No puede hacer esto en MySQL porque "InnoDB verifica las restricciones ÚNICAS y EXTRANJERAS fila por fila" .
Entonces, en Postgres lo siguiente coincidirá con sus requisitos:
Probado en: SQL-Fiddle
Si intenta agregar una fila
(1,5)
:Falla con:
Además, puede agregar una
CHECK
restricción si desea prohibir(y,y)
filas:Hay otras formas de implementar esto como usted menciona, como almacenar solo una dirección de la relación (en una fila, no dos) forzando la identificación inferior
x_id1
y la identificación superior en lax_id2
columna. Parece más fácil de implementar, pero generalmente lleva a consultas más complejas más adelante:fuente