Eu tenho que modelar uma situação onde eu tenho uma tabela Chequing_Account (que contém orçamento, número iban e outros detalhes da conta) que tem que estar relacionada a duas tabelas diferentes Pessoa e Corporação que ambas podem ter 0, 1 ou muitas contas correntes.
Em outras palavras, tenho dois relacionamentos de 1 para muitos com a mesma tabela Conta corrente
Gostaria de ouvir soluções para este problema que respeitem os requisitos de normalização. A maioria das soluções que ouvi por aí são:
1) encontre uma entidade comum da qual pertençam tanto Pessoa quanto Corporação e crie uma tabela de links entre esta e a tabela Chequing_Account, isso não é possível no meu caso e mesmo que fosse eu quero resolver o problema geral e não essa instância específica.
2) Crie duas tabelas de link PersonToChequingAccount e CorporationToChequingAccount que relacionem as duas entidades com as Contas Correntes. No entanto, não quero que duas pessoas tenham a mesma conta corrente, e não quero que uma pessoa física e uma corporação compartilhem uma conta corrente! veja esta imagem
3) Crie duas chaves estrangeiras na Conta Corrente que apontam para Corporação e Pessoa Física, no entanto, eu imporia que uma Pessoa e uma Empresa podem ter muitas contas correntes, mas eu teria que garantir manualmente que para cada linha Conta Corrente nem ambas as relações apontem para Pessoa Jurídica e Pessoa Física porque uma conta corrente é de uma pessoa jurídica ou de uma Pessoa Física. veja esta imagem
Existe alguma outra solução mais limpa para este problema?
Bancos de dados relacionais não são construídos para lidar com essa situação perfeitamente. Você tem que decidir o que é mais importante para você e depois fazer suas trocas. Você tem vários objetivos:
O problema é que alguns desses objetivos competem entre si.
Solução de subdigitação
Você pode escolher uma solução de subdigitação na qual cria um supertipo que incorpora empresas e pessoas. Esse supertipo provavelmente teria uma chave composta da chave natural do subtipo mais um atributo de particionamento (por exemplo
customer_type
, ). Isso é bom no que diz respeito à normalização e permite que você imponha a integridade referencial, bem como a restrição de que corporações e pessoas sejam mutuamente exclusivas. O problema é que isso torna a recuperação de dados mais difícil, porque você sempre tem que ramificar com base emcustomer_type
quando você associa a conta ao titular da conta. Isso provavelmente significa usarUNION
e ter muito SQL repetitivo em sua consulta.Solução de duas chaves estrangeiras
Você pode escolher uma solução em que mantém duas chaves estrangeiras em sua tabela de contas, uma para corporação e outra para pessoa física. Esta solução também permite manter a integridade referencial, normalização e exclusividade mútua. Ele também tem a mesma desvantagem de recuperação de dados que a solução de subdigitação. Na verdade, essa solução é como a solução de subdigitação, exceto que você chega ao problema de ramificar sua lógica de junção "mais cedo".
No entanto, muitos modeladores de dados considerariam essa solução inferior à solução de subdigitação devido à maneira como a restrição de exclusividade mútua é aplicada. Na solução de subdigitação, você usa chaves para impor a exclusividade mútua. Na solução de duas chaves estrangeiras, você usa uma
CHECK
restrição. Conheço algumas pessoas que têm um viés injustificado contra restrições de cheque. Essas pessoas prefeririam a solução que mantém as restrições nas chaves.Solução de Atributo de Particionamento "Desnormalizado"
Existe outra opção onde você mantém uma única coluna de chave estrangeira na tabela de conta corrente e usa outra coluna para lhe dizer como interpretar a coluna de chave estrangeira (RoKa's
OwnerTypeID
coluna). Isso elimina essencialmente a tabela de supertipos na solução de subtipagem desnormalizando o atributo de particionamento para a tabela filho. (Observe que isso não é estritamente "desnormalização" de acordo com a definição formal, porque o atributo de particionamento faz parte de uma chave primária.) Essa solução parece bastante simples, pois evita ter uma tabela extra para fazer mais ou menos a mesma coisa e reduz o número de colunas de chave estrangeira para um. O problema com esta solução é que ela não evita a ramificação da lógica de recuperação e, além disso, não permite que você mantenha a integridade referencial declarativa . Os bancos de dados SQL não têm a capacidade de gerenciar uma única coluna de chave estrangeira para uma das várias tabelas pai.Solução de domínio de chave primária compartilhada
Uma maneira que as pessoas às vezes lidam com esse problema é usar um único conjunto de IDs para que não haja confusão para qualquer ID, se pertence a um subtipo ou a outro. Isso provavelmente funcionaria naturalmente em um cenário bancário, já que você não emitirá o mesmo número de conta bancária para uma corporação e uma pessoa física. Isso tem a vantagem de evitar a necessidade de um atributo de particionamento. Você pode fazer isso com ou sem uma tabela super-tipo. O uso de uma tabela de supertipo permite que você use restrições declarativas para impor exclusividade. Caso contrário, isso teria que ser aplicado processualmente. Essa solução é normalizada, mas não permitirá que você mantenha a integridade referencial declarativa, a menos que você mantenha a tabela de supertipos. Ainda não faz nada para evitar a lógica de recuperação complexa.
Você pode ver, portanto, que não é realmente possível ter um design limpo que siga todas as regras e, ao mesmo tempo, manter a recuperação de dados simples. Você tem que decidir onde serão seus trade-offs.