É possível restringir uma tabela para ter um valor em apenas uma de um conjunto de colunas
-
05-07-2019 - |
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.
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 ??em> 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.