Design do banco de dados: dois relacionamentos de 1 a muitos na mesma tabela

20

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

http://i41.tinypic.com/35i6kbk.png

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

http://i40.tinypic.com/1rpv9z.png

Existe alguma outra solução mais limpa para esse problema?

dendini
fonte
Você já pensou em ter, por exemplo, um OwnerTypeIDna ChecquingAccounttabela, com 1=Corporatione 2=NaturalPerson? Dessa forma, você só precisa de um OwnerIDna ChecquingAccounttabela, que pode ser indexado junto com o OwnerTypeID.
21713 RoKa
Eu preciso não apenas saber se é uma empresa ou pessoa física, mas também conhecer o respectivo ID; portanto, preciso de um número de ID e não apenas de 1 ou 2! Solução 3 é o que eu encontrei aqui eu tenho duas colunas com ids a empresa ou pessoa singular
dendini
2
Sim, a solução é uma opção válida. Na maioria dos DBMS, você pode impor que apenas um dos dois FKs esteja "ativo" com uma restrição de verificação: 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".
ypercubeᵀᴹ
Sim, eu entendo, mas você pode ter na ChecquingAccounttabela um registro de OwnerTypeID=1e OwnerID=123, indicando que é um tipo Corporation, portanto, ID 123na Corporationtabela. O OwnerTypeID informa qual tabela e o OwnerID informa o ID nessa tabela.
21713 RoKa
1
Como é impossível a opção 1? A palavra "corporação" basicamente significa "uma empresa que é legalmente uma pessoa", afinal. Chame de Customersmesa.
Jon of All Trades

Respostas:

15

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:

  • Manter a terceira forma normal
  • Manter a integridade referencial
  • Mantenha a restrição de que cada conta pertence a uma corporação ou a uma pessoa natural.
  • Preserve a capacidade de recuperar dados de maneira simples e direta

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 ramificar customer_typequando se associa à conta do titular da conta. Provavelmente, isso significa usar UNIONe 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 CHECKrestriçã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'sOwnerTypeIDcoluna). 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.

Joel Brown
fonte
Minha solução 2 a qual dos quatro grupos pertence? O "desnormalizado Partitioning Atributo Solution" não é muito claro para mim ..
dendini
@ dendini - Sua solução número 2 não se encaixa em nenhuma das soluções que descrevi. Isso ocorre porque ele não se encaixa no requisito de uma conta pertencente a uma entidade legal. Da maneira como você definiu as chaves primárias das tabelas intermediárias, elas são interseções de muitos para muitos. Se as chaves primárias fossem justas corporation_id e person_idvocê 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.
Joel Brown
Ótima explicação. @JoelBrown, quais são as implicações de desempenho da solução "Duas chaves estrangeiras", em termos de consulta? Além disso, considerando que, em vez de 2, pode haver 6 ou mais chaves estrangeiras: você ainda recomendaria essa abordagem ou preferiria uma diferente?
Amadeo Gallardo
1
@AmadeoGallardo A resposta é "depende". A consulta em uma chave é sempre bastante eficiente, pois geralmente você pode contar com uma verificação de índice pelo menos, se não uma busca, e essas são operações rápidas. O problema ocorre quando você consulta as duas chaves na solução de duas chaves estrangeiras . Aqui, você está solicitando ao otimizador de consulta que efetue uma operação de operação. Na melhor das hipóteses, isso dobrará o custo da consulta, geralmente um pouco pior, pois você deve consultar uma chave e depois a outra e depois mesclar os resultados.
Joel Brown
As futuras versões SQL desordenadas do @JoelBrown devem permitir essa abordagem, permitindo a definição de uma chave estrangeira composta com base em duas colunas RefIDe RefTableonde RefTableexiste 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 isso key.
djmj