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

No SQL, é aceitável que duas tabelas se refiram uma à outra?


Não, não está ok. Referências circulares entre tabelas são confusas. Veja este artigo (há uma década):SQL By Design:The Circular Reference

Alguns DBMS podem lidar com isso e com cuidado especial, mas o MySQL terá problemas.

Opção 1

Como seu projeto, para tornar um dos dois FKs anuláveis. Isso permite que você resolva o problema do ovo e da galinha (em qual tabela devo inserir primeiro?).

Porém, há um problema com seu código. Isso permitirá que um produto tenha uma imagem padrão onde essa imagem fará referência a outro produto!

Para não permitir tal erro, sua restrição FK deve 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

Isso exigirá um UNIQUE restrição/índice na tabela products_pictures em (product_id, id) para que o FK acima seja definido e funcione corretamente.

Opção 2

Outra abordagem é remover o Default_Picture_ID coluna do product table e adicione um IsDefault BIT coluna na picture tabela. O problema com esta solução é como permitir que apenas uma imagem por produto tenha esse bit e todas as outras o desativem. No SQL-Server (e acho que no Postgres) isso pode ser feito com um índice parcial:
CREATE UNIQUE INDEX is_DefaultPicture 
  ON products_pictures (Product_ID)
  WHERE IsDefault = 1 ;

Mas o MySQL não tem esse recurso.

Opção 3

Essa abordagem permite que você tenha as duas colunas FK definidas como NOT NULL é usar restrições adiáveis. Isso funciona no PostgreSQL e acho que no Oracle. Verifique esta pergunta e a resposta de @Erwin:Restrição de chave estrangeira complexa no SQLAlchemy (as Todas as colunas-chave NÃO NULAS Papel).

Restrições no MySQL não podem ser postergadas.

Opção 4

A abordagem (que acho mais limpa) é remover o Default_Picture_ID coluna e adicione outra tabela. Nenhum caminho circular nas restrições FK e todas as colunas FK serão NOT NULL com esta solução:
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)

Isso também exigirá um UNIQUE restrição/índice na tabela products_pictures em (product_id, id) como na solução 1.

Para resumir, com o MySQL você tem duas opções:

  • opção 1 (uma coluna FK anulável) com a correção acima para impor a integridade corretamente

  • opção 4 (sem colunas FK anuláveis)