Modelagem de Dados: O que é um bom design relacional quando uma tabela tem vários constrainst chave estrangeira para uma única tabela?

StackOverflow https://stackoverflow.com/questions/432320

  •  08-07-2019
  •  | 
  •  

Pergunta

Eu tenho 2 tabelas: 1. Os funcionários 2. Vouchers

tabela

Os funcionários tem uma única chave primária. mesa Vouchers tem 3 restrições de chave estrangeira referenciando a tabela Funcionários.

A seguir é um exemplo de script T-SQL (não o script de tabela real) para criar ambas as tabelas e suas relações no SQL Server:

IF OBJECT_ID('dbo.Vouchers') IS NOT NULL
    DROP TABLE dbo.Vouchers
IF OBJECT_ID('dbo.Employees') IS NOT NULL
    DROP TABLE dbo.Employees
GO

CREATE TABLE Employees
(
  ObjectID     INT    NOT NULL   PRIMARY KEY    IDENTITY
)

CREATE TABLE Vouchers
(
  ObjectID     INT    NOT NULL   PRIMARY KEY    IDENTITY,
  IssuedBy     INT,
  ReceivedBy   INT,
  ApprovedBy   INT,

  CONSTRAINT fk_Vouchers_Employees_IssuedBy FOREIGN KEY (IssuedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION,
 CONSTRAINT fk_Vouchers_Employees_ReceivedBy FOREIGN KEY (ReceivedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION,
 CONSTRAINT fk_Vouchers_Employees_ApprovedBy FOREIGN KEY (ApprovedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION 
)

Mas um erro é lançado:

Msg 1785, Level 16, State 0, Line 7
Introducing FOREIGN KEY constraint 'fk_Vouchers_Employees_ReceivedBy' on table 'Vouchers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

Eu não tenho uma idéia do que solução eficiente está disponível aqui. Os requisitos relativos a relação é que: Sempre que um trabalhador é excluído, o voucher que referências algumas de suas colunas para o trabalhador não ficar excluído (ON DELETE CASCADE não é uma opção). Em vez disso, os valores das colunas (emitida pela, ReceivedBy e / ou ApprovedBy) que são referenciados ao excluídos do empregado deve ser definido como NULL (uma vez que as colunas são NULLABLE).

Muito obrigado!

Foi útil?

Solução

estritamente do ponto de design de vista relacional, a tabela de Vouchers como três chaves estrangeiras. Se você optar por aplicá-las, através de afirmações em cascata ou de outra forma, é um problema de implementação, mas o design relacional ainda existe. Presumivelmente você deseja impor que, se um dos três campos não é NULL, em seguida, um registro correspondente precisa existir. Ou não. É um problema de implementação quanto à possibilidade ou não se importa de fazer cumprir o projeto.

No entanto, as violações que você descreve são assumidos no seu perigo. O fato de que você está fazendo esta pergunta sugere que você não pode apreciar plenamente todas as maneiras estas escolhas podem levar para o pântano.

Eu acho que o erro pode ser uma consequência do fato de que mais de um dos três pode referir-se ao mesmo trabalhador.

BTW, eu tenho em muito poucos casos nunca achou necessário excluir registros em tal maneira a que CASCADES são úteis. Normalmente, que seria usado para impedir que o banco de dados seja muito grande; ea capacidade do banco de dados é cada vez menos um problema ao longo do tempo.

Outras dicas

Gostaria de funcionários na verdade não apagar, mas sim usar um gatilho para definir um sinalizador para marcá-los como excluída.

Eu geralmente não ligar cascata de atualizações ou exclusões, mas exigem um aplicativo para executar explicitamente estas ações.

Do ponto de vista de design parece bom ter as 3 chaves estrangeiras que você listou. Parece que a mensagem de erro que você está recebendo relaciona-se com as opções ON UPDATE CASCADE sobre suas chaves estrangeiras (embora eu era capaz de criar a tabela conforme especificado). Independentemente disso, para obter o comportamento você menciona querer, eu recomendaria um gatilho na tabela Funcionários, que é acionado antes de excluir o registro. Esse gatilho iria encontrar instâncias do Employees.OjbectID na tabela de Vouchers e configurá-los para NULL.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top