Outra maneira (sem Nulos e sem ciclos nos FOREIGN KEY
relacionamentos) é ter uma terceira tabela para armazenar os "filhos favoritos". Na maioria dos DBMS, você precisará de uma UNIQUE
restrição adicional TableB
.
O @Aaron foi mais rápido ao identificar que a convenção de nomenclatura acima é bastante complicada e pode levar a erros. Geralmente é melhor (e manterá você saudável) se você não tiver Id
colunas em todas as suas tabelas e se as colunas (que estão unidas) tiverem o mesmo nome nas muitas tabelas que aparecerem. Então, aqui está uma renomeação:
Parent
ParentID INT NOT NULL PRIMARY KEY
Child
ChildID INT NOT NULL PRIMARY KEY
ParentID INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
UNIQUE (ParentID, ChildID)
FavoriteChild
ParentID INT NOT NULL PRIMARY KEY
ChildID INT NOT NULL
FOREIGN KEY (ParentID, ChildID)
REFERENCES Child (ParentID, ChildID)
No SQL-Server (que você está usando), você também tem a opção da IsFavorite
coluna de bits mencionada. O filho favorito único por pai / mãe pode ser realizado por meio de um Índice Único filtrado:
Parent
ParentID INT NOT NULL PRIMARY KEY
Child
ChildID INT NOT NULL PRIMARY KEY
ParentID INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
IsFavorite BIT NOT NULL
CREATE UNIQUE INDEX is_FavoriteChild
ON Child (ParentID)
WHERE IsFavorite = 1 ;
E o principal motivo pelo qual sua opção 1 não é recomendada, pelo menos não no SQL-Server, é que o padrão de caminhos circulares nas referências de chave estrangeira apresenta alguns problemas.
Leia um artigo bastante antigo: SQL por design: a referência circular
Ao inserir ou excluir linhas das duas tabelas, você encontrará o problema "galinha e ovo". Qual tabela devo inserir primeiro - sem violar nenhuma restrição?
Para resolver isso, é necessário definir pelo menos uma coluna anulável. (OK, tecnicamente não é necessário, você pode ter todas as colunas, NOT NULL
mas apenas no DBMS, como Postgres e Oracle, que implementaram restrições adiadas. Consulte a resposta de Erwin em uma pergunta semelhante: Restrição de chave estrangeira complexa no SQLAlchemy sobre como isso pode ser feito no Postgres). Ainda assim, essa configuração parece patinar em gelo fino.
Verifique também uma pergunta quase idêntica no SO (mas no MySQL). No SQL, é correto que duas tabelas se refiram? onde minha resposta é praticamente a mesma. O MySQL não possui índices parciais, portanto, as únicas opções viáveis são o FK anulável e a solução extra de tabela.