Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MySQL:Duas relações n:1, mas não as duas ao mesmo tempo


Seu design atual é chamado de arcos exclusivos onde o sets table tem duas chaves estrangeiras e precisa que exatamente uma delas seja não nula. Essa é uma maneira de implementar associações polimórficas, pois uma determinada chave estrangeira pode referenciar apenas uma tabela de destino.

Outra solução é fazer uma "supertabela" comum que ambos os users e schools referências e, em seguida, use isso como pai 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

Você pode pensar nisso como análogo a uma interface na modelagem OO:
interface SetOwner { ... }

class User implements SetOwner { ... }

class School implements SetOwner { ... }

class Set {
  SetOwner owner;
}

Re seus comentários:

Deixe a tabela SetOwners gerar valores de id. Você precisa inserir em SetOwners antes de poder inserir em Usuários ou Escolas. Portanto, faça com que os IDs em Usuários e Escolas não auto-incremento; basta usar o valor que foi gerado por SetOwners:
INSERT INTO SetOwners DEFAULT VALUES; -- generates an id
INSERT INTO Schools (id, name, location) VALUES (LAST_INSERT_ID(), 'name', 'location');

Dessa forma, nenhum valor de id fornecido será usado para uma escola e um usuário.

Você certamente pode fazer isso. Na verdade, pode haver outras colunas que sejam comuns a Usuários e Escolas, e você pode colocar essas colunas na supertabela SetOwners. Isso entra na herança de tabela de classe de Martin Fowler padronizar.

Você precisa fazer uma associação. Se você estiver consultando a partir de um determinado conjunto e souber que ele pertence a um usuário (não a uma escola), você pode pular ingressar em SetOwners e ingressar diretamente em Users. As junções não precisam necessariamente passar por chaves estrangeiras.
SELECT u.name FROM Sets s JOIN Users u ON s.SetOwner_id = u.id WHERE ...

Se você não sabe se um determinado conjunto pertence a um usuário ou uma escola, você teria que fazer uma junção 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 ...

Você sabe que o SetOwner_id deve corresponder a uma ou outra tabela, Usuários ou Escolas, mas não a ambas.