Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como você pode representar herança em um banco de dados?


@Bill Karwin descreve três modelos de herança em seu livro SQL Antipatterns, ao propor soluções para o antipattern SQL Entity-Attribute-Value. Esta é uma breve visão geral:

Herança de tabela única (também conhecida como herança de tabela por hierarquia):


Usar uma única tabela como em sua primeira opção é provavelmente o design mais simples. Como você mencionou, muitos atributos que são específicos do subtipo terão que receber um NULL valor em linhas onde esses atributos não se aplicam. Com este modelo, você teria uma tabela de políticas, que ficaria mais ou menos assim:
+------+---------------------+----------+----------------+------------------+
| id   | date_issued         | type     | vehicle_reg_no | property_address |
+------+---------------------+----------+----------------+------------------+
|    1 | 2010-08-20 12:00:00 | MOTOR    | 01-A-04004     | NULL             |
|    2 | 2010-08-20 13:00:00 | MOTOR    | 02-B-01010     | NULL             |
|    3 | 2010-08-20 14:00:00 | PROPERTY | NULL           | Oxford Street    |
|    4 | 2010-08-20 15:00:00 | MOTOR    | 03-C-02020     | NULL             |
+------+---------------------+----------+----------------+------------------+

\------ COMMON FIELDS -------/          \----- SUBTYPE SPECIFIC FIELDS -----/

Manter o design simples é uma vantagem, mas os principais problemas com essa abordagem são os seguintes:

  • Quando se trata de adicionar novos subtipos, você teria que alterar a tabela para acomodar os atributos que descrevem esses novos objetos. Isso pode se tornar rapidamente problemático quando você tem muitos subtipos ou se planeja adicionar subtipos regularmente.

  • O banco de dados não poderá impor quais atributos se aplicam e quais não, pois não há metadados para definir quais atributos pertencem a quais subtipos.

  • Você também não pode impor NOT NULL em atributos de um subtipo que deveriam ser obrigatórios. Você teria que lidar com isso em seu aplicativo, o que em geral não é o ideal.

Herança de tabela de concreto:


Outra abordagem para lidar com a herança é criar uma nova tabela para cada subtipo, repetindo todos os atributos comuns em cada tabela. Por exemplo:
--// Table: policies_motor
+------+---------------------+----------------+
| id   | date_issued         | vehicle_reg_no |
+------+---------------------+----------------+
|    1 | 2010-08-20 12:00:00 | 01-A-04004     |
|    2 | 2010-08-20 13:00:00 | 02-B-01010     |
|    3 | 2010-08-20 15:00:00 | 03-C-02020     |
+------+---------------------+----------------+
                          
--// Table: policies_property    
+------+---------------------+------------------+
| id   | date_issued         | property_address |
+------+---------------------+------------------+
|    1 | 2010-08-20 14:00:00 | Oxford Street    |   
+------+---------------------+------------------+

Esse design basicamente resolverá os problemas identificados para o método de tabela única:

  • Atributos obrigatórios agora podem ser aplicados com NOT NULL .

  • Adicionar um novo subtipo requer adicionar uma nova tabela em vez de adicionar colunas a uma existente.

  • Também não há risco de que um atributo inadequado seja definido para um subtipo específico, como o vehicle_reg_no campo para uma política de propriedade.

  • Não há necessidade do type atributo como no método de tabela única. O tipo agora é definido pelos metadados:o nome da tabela.

No entanto, este modelo também apresenta algumas desvantagens:

  • Os atributos comuns são misturados com os atributos específicos do subtipo e não há uma maneira fácil de identificá-los. O banco de dados também não saberá.

  • Ao definir as tabelas, você teria que repetir os atributos comuns para cada tabela de subtipo. Isso definitivamente não é SECO.

  • Pesquisar todas as políticas, independentemente do subtipo, torna-se difícil e exigiria um monte de UNION s.

É assim que você teria que consultar todas as políticas, independentemente do tipo:
SELECT     date_issued, other_common_fields, 'MOTOR' AS type
FROM       policies_motor
UNION ALL
SELECT     date_issued, other_common_fields, 'PROPERTY' AS type
FROM       policies_property;

Observe como a adição de novos subtipos exigiria que a consulta acima fosse modificada com um UNION ALL adicional para cada subtipo. Isso pode facilmente levar a bugs em seu aplicativo se essa operação for esquecida.

Herança de tabela de classe (também conhecida como herança de tabela por tipo):


Esta é a solução que @David menciona na outra resposta. Você cria uma única tabela para sua classe base, que inclui todos os atributos comuns. Em seguida, você criaria tabelas específicas para cada subtipo, cuja chave primária também serve como chave estrangeira para a tabela base. Exemplo:
CREATE TABLE policies (
   policy_id          int,
   date_issued        datetime,

   -- // other common attributes ...
);

CREATE TABLE policy_motor (
    policy_id         int,
    vehicle_reg_no    varchar(20),

   -- // other attributes specific to motor insurance ...

   FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);

CREATE TABLE policy_property (
    policy_id         int,
    property_address  varchar(20),

   -- // other attributes specific to property insurance ...

   FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);

Esta solução resolve os problemas identificados nos outros dois projetos:

  • Atributos obrigatórios podem ser aplicados com NOT NULL .

  • Adicionar um novo subtipo requer adicionar uma nova tabela em vez de adicionar colunas a uma existente.

  • Não há risco de que um atributo inadequado seja definido para um subtipo específico.

  • Não há necessidade do type atributo.

  • Agora os atributos comuns não são mais misturados com os atributos específicos do subtipo.

  • Podemos ficar SECOS, finalmente. Não há necessidade de repetir os atributos comuns para cada tabela de subtipo ao criar as tabelas.

  • Gerenciando um id de incremento automático para as políticas torna-se mais fácil, porque isso pode ser tratado pela tabela base, em vez de cada tabela de subtipo gerá-las independentemente.

  • Pesquisar todas as políticas, independentemente do subtipo, agora se torna muito fácil:Não UNION s necessário - apenas uma SELECT * FROM policies .

Considero a abordagem da tabela de classes como a mais adequada na maioria das situações.

Os nomes desses três modelos vêm do livro Patterns of Enterprise Application Architecture de Martin Fowler.