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

MySQL:dos relaciones n:1, pero no ambas a la vez

Su diseño actual se llama arcos exclusivos donde el sets table tiene dos claves foráneas y necesita que exactamente una de ellas sea no nula. Esta es una forma de implementar asociaciones polimórficas, ya que una clave externa dada puede hacer referencia solo a una tabla de destino.

Otra solución es hacer una "supertabla" común que ambos users y schools referencias, y luego usar eso como padre de sets .

create table set_owner

create table users 
  PK is also FK --> set_owner

create table schools
  PK is also FK --> set_owner

create table sets 
  FK --> set_owner

Puede pensar en esto como análogo a una interfaz en modelado OO:

interface SetOwner { ... }

class User implements SetOwner { ... }

class School implements SetOwner { ... }

class Set {
  SetOwner owner;
}

Re sus comentarios:

Deje que la tabla SetOwners genere valores de identificación. Debe insertarse en SetOwners antes de poder insertarse en Usuarios o Escuelas. Así que haga las identificaciones en Usuarios y Escuelas no incremento automático; solo use el valor que fue generado por SetOwners:

INSERT INTO SetOwners DEFAULT VALUES; -- generates an id
INSERT INTO Schools (id, name, location) VALUES (LAST_INSERT_ID(), 'name', 'location');

De esta manera, no se utilizará ningún valor de identificación dado para una escuela y un usuario.

Ciertamente puedes hacer esto. De hecho, puede haber otras columnas que sean comunes tanto para Usuarios como para Escuelas, y podría poner estas columnas en la supertabla SetOwners. Esto entra en Herencia de tablas de clases de Martin Fowler patrón.

Necesitas hacer una unión. Si está consultando desde un Conjunto determinado y sabe que pertenece a un usuario (no a una escuela), puede omitir unirse a SetOwners y unirse directamente a Usuarios. Las uniones no necesariamente tienen que ir por claves foráneas.

SELECT u.name FROM Sets s JOIN Users u ON s.SetOwner_id = u.id WHERE ...

Si no sabe si un conjunto determinado pertenece a un usuario o a una escuela, debe hacer una combinación externa para ambos:

SELECT COALESCE(u.name, sc.name) AS name 
FROM Sets s 
LEFT OUTER JOIN Users u ON s.SetOwner_id = u.id
LEFT OUTER JOIN Schools sc ON s.SetOwner_id = sc.id 
WHERE ...

Sabe que SetOwner_id debe coincidir con una u otra tabla, Usuarios o Escuelas, pero no con ambas.