Qual é a melhor maneira de modelar o seguinte relacionamento de tipo?
Digamos que eu tenha tabelas representando dois tipos de entidades: company
e person
. Eu tenho uma customer
tabela com um entity_id
campo, que deve se referir a a company
ou a person
.
Se eu simplesmente armazenar a company_id
ou a , não saberei em qual tabela procurar a entidade. A primeira solução que me ocorreu é ter um person_id
campo no qual levaria os valores "empresa" ou "pessoa" para diga-me a qual tabela minha chave estrangeira se refere. Não tenho certeza se esta é a melhor maneira embora.entity_id
entity_type
customer
entity_id
Isso parece ser um problema bastante comum no design de banco de dados, então espero que haja um padrão de design que eu possa adotar.
Eu usei a palavra polimorfismo no título no sentido mais amplo, então não estou me referindo à herança. No meu exemplo, uma empresa não é uma pessoa (ou vice-versa), mas ainda são intercambiáveis. Outras perguntas que encontrei nos sites do Stack Exchange assumiram que a herança também é um requisito, portanto, não tenho certeza de que haja uma duplicata adequada.
Parece haver 2 maneiras principais de modelar tal situação:
(1) Use supertipos/subtipos. No entanto, como não estamos discutindo design "orientado a objetos", a segunda opção pode ser um pouco mais apropriada.
(2) Use o chamado ARC, que expressa uma relação XOR.
Suponha que temos uma entidade TRANSACTION. Cada cliente pode estar envolvido em uma ou mais transações E um cliente é uma EMPRESA ou uma PESSOA (XOR). Nosso modelo ERD/relacional pode ser parecido com os abaixo. Observe o "arco", que é desenhado em ambos os relacionamentos.
Quanto à implementação: você pode codificar uma restrição CHECK (para evitar triggers), que irá impor o XOR (ou exclusivo). O código DDL completo se parece com isso (observe o CHECK):
(Testado no Oracle 12c)
Eu sei que você disse que não está se referindo à herança, mas a melhor literatura sobre o seu caso se refere à herança ao descrever o problema e propor uma solução.
Há um punhado de sites que fornecem soluções detalhadas sobre como projetar tabelas relacionais que expressam o tipo/subtipo ou o relacionamento classe/subclasse. O mais importante é usar as palavras-chave certas em sua pesquisa.
Na modelagem Entidade-Relacionamento entre clientes, empresas e pessoas é chamada de "generalização/especialização". Uma pesquisa sobre isso lhe dará muito material bom. As empresas são clientes especializados, assim como as pessoas. outra palavra-chave útil é "relacionamentos IS-A".
Na modelagem relacional, existem três técnicas amplamente compartilhadas para cobrir esse tipo de problema. Aqui eles são "herança de tabela única", "herança de tabela de classe" e "chave primária compartilhada". Eu sei que a palavra herança aparece lá, mas acredite em mim, uma pesquisa sobre esses itens fornecerá alguns artigos que abordam seu caso específico, embora possam estar falando sobre automóveis, caminhões e veículos ou cães, gatos e animais de estimação. de empresas, pessoas e clientes.
Alguns dos acessos que você receberá o levarão de volta aqui, para stackexchange.dba. Outros o levarão ao Stackoverflow, onde há três tags para coletar informações sobre as três técnicas.
A única coisa não coberta em detalhes é como você adiciona restrições para impor a regra de exclusão mútua, o que você chamou de XOR. Se você usar a chave primária compartilhada, a restrição para exclusão mútua será muito parecida com a que você já apresentou, só que mais simples.
Para resumir o que tudo isso significa no seu caso:
Você terá quatro tabelas: transação, cliente, pessoa e empresa.
A transação conterá um campo customer_id, que faz referência ao campo id em customer. O cliente terá um campo de identificação, provavelmente preenchido por um recurso de numeração automática, como é feito normalmente. A pessoa não tem um campo id. Em vez disso, ele tem um campo company_id que atua como uma chave primária e uma chave estrangeira que faz referência a company.id. A empresa é tratada da mesma forma que a pessoa, com um campo company_id que é um PK e um FK.
A tabela de clientes pode conter campos, se houver, que pertencem a empresas e pessoas.
Por fim, você precisará de uma restrição na tabela person que diga que customer_id não está na tabela company e uma na tabela company que diga que customer_id não está na tabela person.