Eu tenho uma tabela onde as linhas podem estar relacionadas entre si e, logicamente, a relação ocorre nos dois sentidos (basicamente, é sem direção) entre as duas linhas. (E se você está se perguntando, sim, isso realmente deveria ser uma tabela. São duas coisas exatamente da mesma entidade/tipo lógico.) Posso pensar em algumas maneiras de representar isso:
- Armazene a relação e seu reverso
- Armazene o relacionamento de uma maneira, restrinja o banco de dados de armazená-lo de outra maneira e tenha dois índices com ordens opostas para os FKs (um índice sendo o índice PK)
- Armazene o relacionamento de uma maneira com dois índices e permita que o segundo seja inserido de qualquer maneira (parece meio nojento, mas ei, completude)
- Crie algum tipo de tabela de agrupamento e tenha um FK para ela na tabela original. (Levanta muitas questões. A tabela de agrupamento teria apenas um número; por que ter a tabela? Tornar FK NULLable ou ter grupos com uma única linha associada?)
Quais são alguns dos principais prós e contras dessas formas e, claro, existe alguma maneira que eu não tenha pensado?
Aqui está um SQLFiddle para brincar: http://sqlfiddle.com/#!12/7ee1a/1/0 . (Acontece que é o PostgreSQL, já que é o que estou usando, mas não acho que essa pergunta seja muito específica do PostgreSQL.) Atualmente, ele armazena o relacionamento e seu reverso apenas como exemplo.
O que você projetou é bom. O que precisa ser adicionado é uma restrição para tornar o relacionamento sem direção. Portanto, você não pode ter uma
(1,5)
linha sem que uma(5,1)
linha seja adicionada também.Isso pode ser feito * com uma restrição de auto-referência na tabela de ponte.
*: pode ser realizado em Postgres, Oracle, DB2 e todos os DBMS que implementaram restrições de chave estrangeira como descrito no padrão SQL (adiado, por exemplo, verificado no final da transação). Servidor que os verifica no final da instrução e esta construção ainda funciona. Você não pode fazer isso no MySQL porque "InnoDB verifica restrições UNIQUE e FOREIGN KEY linha por linha" .
Portanto, no Postgres, o seguinte corresponderá aos seus requisitos:
Testado em: SQL-Fiddle
Se você tentar adicionar uma linha
(1,5)
:Ele falha com:
Além disso, você pode adicionar uma
CHECK
restrição se quiser proibir(y,y)
linhas:Existem outras maneiras de implementar isso como você mencionou, como armazenar apenas uma direção do relacionamento (em uma linha, não duas), forçando o id inferior
x_id1
e o id superior nax_id2
coluna. Parece mais fácil de implementar, mas geralmente leva a consultas mais complexas posteriormente: