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

Pergunta de design de banco de dados sobre chaves estrangeiras anuláveis ​​e normalização


Alguns designers muito bons usam NULLs em chaves estrangeiras sem consequências adversas. Eu mesmo me inclino assim. Um FK anulável representa um relacionamento opcional. Nos casos em que a entidade não tem relacionamento, o FK contém um NULL. A sobrecarga de espaço é mínima. Quando as junções (equijoins, mais precisamente) são feitas nas duas tabelas, as instâncias que contêm NULL no FK sairão da junção, e isso é apropriado.

Dito isso, vou recomendar um quarto método para você. Isso envolve um total de 4 tabelas, contas, widgets, tipos e custom_types. A tabela custom_types usa uma técnica chamada Shared-primary-key, descrita abaixo.
CREATE TABLE accounts (
    account_id  INT UNSIGNED AUTO_INCREMENT NOT NULL, 
    # Other Columns...,
    PRIMARY KEY (account_id)
    );  
CREATE TABLE widgets (
    widget_id   INT UNSIGNED AUTO_INCREMENT NOT NULL,
    account_id  INT UNSIGNED NOT NULL, 
    type_id     INT UNSIGNED NOT NULL,
    PRIMARY KEY (widget_id),
    FOREIGN KEY (account_id) REFERENCES accounts(account_id) ON DELETE CASCADE,
    FOREIGN KEY (type_id) REFERENCES types(type_id)
    );  
CREATE TABLE types (
    type_id     INT UNSIGNED AUTO_INCREMENT NOT NULL,
    account_id  INT UNSIGNED NOT NULL, 
    name        VARCHAR(100) NOT NULL,
    PRIMARY KEY (type_id),
    FOREIGN KEY (account_id) REFERENCES accounts(account_id)
CREATE TABLE custom_types (
    type_id     INT NOT NULL,
    account_id  INT UNSIGNED NOT NULL, 
    PRIMARY KEY (type_id),
    FOREIGN KEY (type_id) REFERENCES types(type_id),
    FOREIGN KEY (account_id) REFERENCES accounts(account_id)

);

A coluna type_id em custom_types é uma chave primária compartilhada. Observe que ele é declarado AMBOS como chave primária e como chave estrangeira, e que não usa autonumber. É uma cópia da chave primária em tipos para a entrada correspondente. A tabela de tipos personalizados contém todos os dados presentes nos tipos personalizados, mas ausentes nos tipos predefinidos.

Para tipos predefinidos, uma entrada é feita em tipos, mas nenhuma entrada é feita em custom_types. Para custom_types, uma entrada é feita primeiro em tipos e, em seguida, o valor resultante de type_id é copiado para custom_types, junto com o account_id.

Se você usar os tipos INNER JOIN e custom_types, os tipos predefinidos serão excluídos da junção. Se você deseja tipos personalizados e predefinidos em uma única junção, você deve usar um LEFT JOIN ou um RIGHT JOIN para obter esse efeito. Observe que o resultado de um LEFT ou RIGHT JOIN conterá alguns NULLs, mesmo que esses NULLs não sejam armazenados no banco de dados.

Clicar nesta fornecerá uma descrição mais detalhada da técnica de chave primária compartilhada.