Estou procurando uma "melhor prática" ou "padrão" específica sobre entidades que são compartilhadas entre diferentes entidades, tendo uma relação com uma de muitas.
Por exemplo, pode-se ter a entidade genérica "Endereço", que poderia ser utilizada para armazenar os campos de endereços comuns para clientes, fornecedores, funcionários, etc...
Um DBA experiente seguiria esse caminho ou preferiria adicionar os campos às entidades correspondentes? Também estou pensando em manutenção, restrições que podem (no futuro) diferir dependendo da entidade, coisas assim.
Eu adoraria obter referências a qualquer trabalho autoritário ou estabelecido sobre o assunto.
A motivação para empilhar todo tipo de endereço em uma única tabela geralmente é uma má interpretação e aplicação incorreta da noção de reutilização de código.
As pessoas podem cometer o erro de presumir que, como você tem duas entidades com algum conjunto comum de atributos, esses atributos pertencem à sua própria tabela. Às vezes, as entidades têm colunas semelhantes ou idênticas coincidentemente . Ninguém criaria uma tabela para cada
NAME
ou em seu bancoDESCRIPTION
deEFFECTIVE_DATE
dados, pelo menos espero que não seja tentado a fazer isso.Algumas pessoas se referem erroneamente a todas as instâncias de remoção de colunas de suas próprias tabelas como normalização . A normalização envolve a remoção de colunas para suas próprias tabelas, mas nem todas as instâncias de remoção de colunas dessa maneira são realmente normalização. A normalização prescreve razões muito específicas para remover colunas de uma tabela. Se nenhum desses motivos for aplicável, você não está normalizando, está apenas complicando as coisas.
Você tem duas maneiras corretas de pensar sobre isso: ou todos os seus endereços pertencem a uma pilha porque você tem um supertipo de entidade que incorpora todos os recursos comuns de vários subtipos de entidade, incluindo endereços, - ou - seus endereços pertencem a pilhas separadas (tabelas) de acordo com cada tipo de coisa que possui um endereço e você escreve seu código de procedimento em uma interface IAddress que é implementada para cada tabela de endereços.
Se você realmente tem um supertipo de entidade, digamos
LEGAL_ENTITY
que tenha subtipos comoCUSTOMER
,VENDOR
,EMPLOYEE
e assim por diante, então ter umaADDRESS
tabela que é filha deLEGAL_ENTITY
é uma abordagem legítima. Pode até ser uma abordagem valiosa se houver uma sobreposição significativa entre seus clientes, fornecedores, funcionários (ou o que quer que você esteja rastreando), porque você pode alterar os endereços uma vez em vez de vários locais quando uma entidade legal se move. Por outro lado, se você não tiver esse supertipo, enfrentará os problemas apontados por Richard Tallent.Se você mantiver seus endereços em tabelas diferentes de acordo com o tipo de entidade que possui o endereço, ainda poderá obter a reutilização de código, assumindo que o idioma que você está usando oferece suporte a interfaces.
Como um aparte: tvCa apontou em um comentário que os endereços podem ser armazenados como colunas em vez de linhas em uma tabela separada. Isso dependerá muito de quantos endereços você precisa para cada entidade. Se você estiver rastreando dois endereços (físico, postal) ou se estiver armazenando o histórico de endereços, use uma tabela de endereços. Se você armazenar apenas um endereço por destinatário, uma tabela separada provavelmente será um exagero.
Não posso apontar nada confiável, mas se você pensar nos detalhes de tal implementação, as possíveis desvantagens são evidentes.
Ter uma tabela subsidiária "compartilhada" é problemático principalmente porque se duas tabelas "pai" (digamos,
Customer
eEmployee
) utilizam a mesmaAddress
tabela para armazenar endereços, você não pode usar uma restrição de chave estrangeira para garantir a integridade referencial entre os registros de endereço e o registros pais correspondentes.Mesmo se você renunciar ao uso de restrições de chave estrangeira, terá alguns problemas ao configurar suas colunas de chave estrangeira. Você basicamente tem três opções, nenhuma das quais é ideal:
Coloque um
AddressID
campo nas tabelas Cliente e Funcionário. Os problemas aqui são (1) você não pode garantir que um endereço não será usado mais de uma vez e (2) seAddressID
for atribuído automaticamente, você não poderá armazenar o endereço na tabela Cliente/Funcionário até que o Endereço é criado, que é o contrário de como você provavelmente deseja inserir os registros ( ou seja , tornaAddress
a tabela "pai").Coloque
CustomerID
eEmployeeID
colunas naAddress
tabela. Os problemas aqui incluem (1) novamente, você não pode garantir o uso duplo de um endereço, (2) desperdiça espaço, pois está armazenando um NULL em uma coluna ou outra e (3) não escala bem conforme você encontra mais entidades que precisam de endereços.Recolher CustomerID/EmployeeID/etc. em uma única coluna
ParentID
e outra colunaParentTypeID
que se distingueCustomers
deEmployees
. Isso é melhor dimensionado do que (2) acima, mas tem seus próprios problemas, como a necessidade de atribuir "números mágicos" às tabelas pai para o arquivoParentTypeID
.Eu não vou dizer que não há lugares onde tais abordagens não são pragmáticas, mas você tem que considerar se é realmente tão importante ter colunas semelhantes em várias tabelas, e se tentar movê-las para uma tabela comum realmente compra qualquer coisa para o aumento da complexidade em inserções, atualizações, junções, etc. IMHO, geralmente é melhor cada tabela ter restrições claras em como elas se relacionam com outras tabelas e para as tabelas "pai" representarem os principais objetos de negócios que estão sendo criados (clientes, funcionários, etc.), não tipos complexos subsidiários que são comuns a várias outras tabelas.