Tenho que modelar uma situação em que tenho uma tabela Chequing_Account (que contém orçamento, número iban e outros detalhes da conta) que deve estar relacionada a duas tabelas diferentes, Person e Corporation, que podem ter 0, 1 ou muitas contas de chequing.
Em outras palavras, tenho dois relacionamentos 1-para-muitos com a mesma tabela Chequing account
Gostaria de ouvir soluções para este problema que respeitem os requisitos de normalização. A maioria das soluções que ouvi são:
1) encontre uma entidade comum da qual Person e Corporation pertençam e crie uma tabela de links entre essa e a tabela Chequing_Account; isso não é possível no meu caso e, mesmo que eu queira resolver o problema geral e não esta instância específica.
2) Crie duas tabelas de links PersonToChequingAccount e CorporationToChequingAccount que relacionam as duas entidades com as Contas de Chequing. No entanto, não quero que duas Pessoas tenham a mesma conta de cheque, e não quero que uma pessoa natural e uma Corporação compartilhem uma conta de cheque! veja esta imagem
3) Crie duas chaves estrangeiras na conta Chequing que apontam para Corporação e Pessoa natural; no entanto, eu aplicaria que uma pessoa e uma empresa possam ter muitas contas chequing; no entanto, eu precisaria garantir manualmente que, para cada linha ChequingAccount, as duas relações não apontem para Corporação e Pessoa Natural porque uma conta corrente é de uma corporação ou de uma Pessoa Natural. veja esta imagem
Existe alguma outra solução mais limpa para esse problema?
fonte
OwnerTypeID
naChecquingAccount
tabela, com1=Corporation
e2=NaturalPerson
? Dessa forma, você só precisa de umOwnerID
naChecquingAccount
tabela, que pode ser indexado junto com oOwnerTypeID
.CHECK (CorporationID IS NOT NULL AND NaturalPersonID IS NULL OR CorporationID IS NULL AND NaturalPersonID IS NOT NULL)
eu prefiro a solução 1 (embora seja apenas eu). É muito "limpo".ChecquingAccount
tabela um registro deOwnerTypeID=1
eOwnerID=123
, indicando que é um tipoCorporation
, portanto, ID123
naCorporation
tabela. O OwnerTypeID informa qual tabela e o OwnerID informa o ID nessa tabela.Customers
mesa.Respostas:
Bancos de dados relacionais não são criados para lidar com essa situação perfeitamente. Você precisa 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 sub-digitação
Você pode escolher uma solução de sub-digitação na qual cria um super-tipo 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 impor a integridade referencial, bem como a restrição de que empresas e pessoas sejam mutuamente exclusivas. O problema é que isso dificulta a recuperação de dados, porque você sempre precisa se ramificarcustomer_type
quando se associa à conta do titular da conta. Provavelmente, isso significa usarUNION
e ter um monte de SQL repetitivo na sua consulta.Solução com duas chaves estrangeiras
Você pode escolher uma solução na qual mantenha duas chaves estrangeiras na tabela da sua conta, uma para a corporação e outra para a pessoa. Essa solução também permite manter a integridade referencial, a normalização e a exclusividade mútua. Ele também tem a mesma desvantagem de recuperação de dados da solução de sub-digitação. De fato, esta solução é como a solução de sub-digitação, exceto que você começa o 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 sub-digitação devido ao modo como a restrição de exclusividade mútua é imposta. Na solução de sub-digitaçã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 cheques. Essas pessoas preferem a solução que mantém as restrições nas chaves.Solução de atributo de particionamento "não-normalizado"
Há outra opção em que você mantém uma única coluna de chave estrangeira na tabela de contas chequing e usa outra coluna para informar como interpretar a coluna de chave estrangeira (RoKa's
OwnerTypeID
coluna). Isso basicamente elimina a tabela de supertipo na solução de sub-digitação, 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 particionamento faz parte de uma chave primária.) Essa solução parece bastante simples, pois evita que uma tabela extra faça 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 de as pessoas às vezes lidarem com esse problema é usar um único pool de IDs, para que não haja confusão para um determinado ID, independentemente de pertencer a um subtipo ou outro. Provavelmente, isso funcionaria naturalmente em um cenário bancário, pois você não emitirá o mesmo número de conta bancária para uma corporação e uma pessoa natural. Isso tem a vantagem de evitar a necessidade de um atributo de particionamento. Você pode fazer isso com ou sem uma tabela de supertipo. O uso de uma tabela de supertipo permite usar restrições declarativas para impor exclusividade. Caso contrário, isso teria que ser aplicado procedimentalmente. Essa solução é normalizada, mas não permitirá que você mantenha a integridade referencial declarativa, a menos que mantenha a tabela de supertipo. Ainda não faz nada para evitar 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, mantendo ao mesmo tempo a recuperação de dados simples. Você tem que decidir onde serão suas compensações.
fonte
corporation_id
eperson_id
você tivesse essencialmente a solução de sub-digitação, exceto que a tabela de supertipo seria dividida em duas e a chave estrangeira seria invertida, para que as pessoas não pudessem manter várias contas. Esse tipo de derrota o propósito.RefID
eRefTable
ondeRefTable
existe um ID fixo que identifica a tabela de destino. Existem muitos casos de uso para esse tipo de chave e é muito importante manter 10 ou mais tabelas de associação / subtipo para reforçar a integridade. Para esses casos, eu mesmo criei issokey
.