É possível restringir uma tabela para ter um valor em apenas uma de um conjunto de colunas

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

Pergunta

Eu tenho uma tabela que precisa de ligação um dos três mesas separadas, mas ele só deve conectar-se a um deles, por exemplo.

Main_Table
id UNIQUEIDENTIFIER
t1_id UNIQUEIDENTIFIER
t2_id INT
t3_id INT

T1
id UNIQUEIDENTIFIER
name VARCHAR(255)

T2
id INT
name VARCHAR(255)

T3
id INT
name VARCHAR(255)

É possível ter uma restrição em que apenas um de T1, T2 ou T3 não é nulo, a qualquer momento um?

É este projeto apenas ruim? Se sim, quais sugestões você daria para o design?

EDIT:

Já me pediram para elaborar as razões por trás deste projeto particular.

Main_Table está a tentar ser uma tabela pagador, o que poderia fazer referência a qualquer um utilizador individual (T1), um grupo de utilizadores individuais (T2), ou um grupo de grupos (T3).

Este é um projeto de banco de dados Eu herdei, e não é realmente sujeitos a mudança, infelizmente.

O meu maior problema é que eu preciso para associar entre diferentes tipos, por isso, um campo de tipo não vai funcionar aqui como os índices são diferentes.

Foi útil?

Solução

O projeto que você está descrevendo é chamado arcos exclusivos . Sim, é um projeto bonito frágil e até mesmo falhar algumas regras de normalização.

Aqui está uma alternativa:

Main_Table
id UNIQUEIDENTIFIER
t_id INT NOT NULL
  FOREIGN KEY (t_id) REFERENCES T0 (id)

T0
id UNIQUEIDENTIFIER
type INT NOT NULL CHECK (type IN (1,2,3))
  UNIQUE KEY (id, type)

T1
id INT 
type INT NOT NULL CHECK (type = 1) 
name VARCHAR(255)
  FOREIGN KEY (id, type) REFERENCES T0 (id, type)

T2
id INT
type INT NOT NULL CHECK (type = 2)
name VARCHAR(255)
  FOREIGN KEY (id, type) REFERENCES T0 (id, type)

T3
id INT
type INT NOT NULL CHECK (type = 3)
name VARCHAR(255)
  FOREIGN KEY (id, type) REFERENCES T0 (id, type)

Com este projeto, cada linha Main_Table deve fazer referência a uma linha na T0.
Da mesma forma, cada linha em T0 pode ser a mãe de apenas uma linha na T1, T2, ou T3.

Esta é uma maneira de implementar classe Herança de tabelas e associações polimórficas sem quebrar a integridade referencial.


Main_Table está tentando ser um pagador mesa, o que poderia fazer referência a qualquer uma usuário individual (T1), um grupo de os utilizadores individuais (T2), ou um grupo de grupos (T3).

Certo, então acho que isso em termos de design orientado a objeto. Se você tivesse três classes que poderiam funcionar como um receptor de pagamentos, você criar um Interface chamado Payable ou algo assim, para que cada você poderia contar com a digitação desses objetos. Todos os objetos Payable deve ter um método sendPayment() por exemplo. Em algumas linguagens OO, a interface é uma superclasse e é chamada de classe abstrata ou classe virtual pura .

As funções de tabela T0 como um tipo comum para cada uma das tabelas filho T1, T2 e T3. Quando Main_Table tem uma chave estrangeira para T0, é como dizer Main_Table deve ter uma referência a alguma entidade que é Payable, mas qualquer objeto descendente a partir desse superclasse é bom para uso.

A coluna type é apenas um truque para se certificar de que um determinado T0.id pode ser referenciado apenas por uma mesa subclasse de cada vez. É o tipo de opcional, se você pode confiar em sua lógica de aplicação para inserir uma determinada linha criança em apenas uma das tabelas subclasses.


Veja também a seção sobre associações polimórficas na minha apresentação " SQL antipadrões Strike Back ."

Outras dicas

Se o seu DB tem restrições de verificação, você pode chicotear acima de um kludge feio como:

ALTER TABLE Main_Table
 add constraint CK_ThisWorksButItsUgly
  check ( (  case when t1_id is null then 0 else 1 end
           + case when t2_id is null then 0 else 1 end
           + case when t3_id is null then 0 else 1 end) = 1)

Alguns da sintaxe pode estar errado lá, mas você começa a idéia. Ele provavelmente iria realizar bem o suficiente - o cheque só teria de fogo quando uma das colunas foi modificado -., Mas nenhuma maneira é bastante

Exlusive Arcs de Bill Karwin são muito legal, se você pode re-arquiteto do projeto de banco de dados.

Além do design ruim, se você não pode alterá-lo, é possível usar um gatilho para impor essa restrição

Este é mais um exemplo do padrão gen-spec.

Go artigos Ogle web sobre "modelagem relacional generalização especialização". Há alguns excelentes lá fora.

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