sql >> Base de Datos >  >> RDS >> Mysql

En SQL, ¿está bien que dos tablas se refieran entre sí?

No, no está bien. Las referencias circulares entre tablas son desordenadas. Consulte este artículo (de hace una década):SQL By Design:The Circular Reference

Algunos DBMS pueden manejarlos, y con especial cuidado, pero MySQL tendrá problemas.

Opción 1

Como su diseño, para hacer que uno de los dos FK sea anulable. Esto le permite resolver el problema del huevo y la gallina (¿en qué tabla debo insertar primero?).

Sin embargo, hay un problema con su código. ¡Permitirá que un producto tenga una imagen predeterminada donde esa imagen hará referencia a otro producto!

Para rechazar tal error, su restricción FK debe ser:

CONSTRAINT FK_products_1 
  FOREIGN KEY (id, default_picture_id) 
  REFERENCES products_pictures (product_id, id)
  ON DELETE RESTRICT                            --- the SET NULL options would 
  ON UPDATE RESTRICT                            --- lead to other issues

Esto requerirá un UNIQUE restricción/índice en la tabla products_pictures en (product_id, id) para que el FK anterior se defina y funcione correctamente.

Opción 2

Otro enfoque es eliminar el Default_Picture_ID columna del product tabla y agregue un IsDefault BIT columna en la picture mesa. El problema con esta solución es cómo permitir que solo una imagen por producto tenga ese bit activado y todas las demás lo tengan desactivado. En SQL-Server (y creo que en Postgres) esto se puede hacer con un índice parcial:

CREATE UNIQUE INDEX is_DefaultPicture 
  ON products_pictures (Product_ID)
  WHERE IsDefault = 1 ;

Pero MySQL no tiene esa característica.

Opción 3

Este enfoque le permite incluso tener ambas columnas FK definidas como NOT NULL es utilizar restricciones diferibles. Esto funciona en PostgreSQL y creo que en Oracle. Verifique esta pregunta y la respuesta de @Erwin:Restricción de clave externa compleja en SQLAlchemy (las Todas las columnas clave NO SON NULAS parte).

Las restricciones en MySQL no se pueden diferir.

Opción 4

El enfoque (que encuentro más limpio) es eliminar el Default_Picture_ID columna y agregue otra tabla. No hay ruta circular en las restricciones FK y todas las columnas FK serán NOT NULL con esta solución:

product_default_picture
----------------------
product_id          NOT NULL
default_picture_id  NOT NULL
PRIMARY KEY (product_id)
FOREIGN KEY (product_id, default_picture_id)
  REFERENCES products_pictures (product_id, id)

Esto también requerirá un UNIQUE restricción/índice en la tabla products_pictures en (product_id, id) como en la solución 1.

Para resumir, con MySQL tienes dos opciones:

  • opción 1 (una columna FK anulable) con la corrección anterior para hacer cumplir la integridad correctamente

  • opción 4 (sin columnas FK anulables)