sql >> Databáze >  >> RDS >> Sqlserver

Jak můžete reprezentovat dědictví v databázi?

@Bill Karwin popisuje tři modely dědičnosti ve své knize SQL Antipatterns, když navrhuje řešení pro antivzor SQL Entity-Attribute-Value. Toto je stručný přehled:

Dědičnost jedné tabulky (neboli dědění tabulky podle hierarchie):

Použití jedné tabulky jako ve vaší první možnosti je pravděpodobně nejjednodušší návrh. Jak jste zmínil, mnoho atributů, které jsou specifické pro podtyp, bude muset mít NULL hodnota na řádcích, kde tyto atributy neplatí. S tímto modelem byste měli jednu tabulku politik, která by vypadala asi takto:

+------+---------------------+----------+----------------+------------------+
| 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 -----/

Udržování jednoduchého designu je výhodou, ale hlavní problémy tohoto přístupu jsou následující:

  • Pokud jde o přidávání nových podtypů, museli byste upravit tabulku tak, aby vyhovovala atributům, které tyto nové objekty popisují. To se může rychle stát problematickým, pokud máte mnoho podtypů nebo pokud plánujete přidávat podtypy pravidelně.

  • Databáze nebude schopna vynutit, které atributy se použijí a které ne, protože neexistují žádná metadata, která by definovala, které atributy patří ke kterým podtypům.

  • Nemůžete také vynutit NOT NULL o atributech podtypu, které by měly být povinné. To byste museli řešit ve své aplikaci, což obecně není ideální.

Dědičnost konkrétní tabulky:

Dalším přístupem k řešení dědičnosti je vytvoření nové tabulky pro každý podtyp opakováním všech společných atributů v každé tabulce. Například:

--// 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    |   
+------+---------------------+------------------+

Tento návrh v podstatě vyřeší problémy identifikované pro metodu jedné tabulky:

  • Povinné atributy lze nyní vynutit pomocí NOT NULL .

  • Přidání nového podtypu vyžaduje přidání nové tabulky namísto přidávání sloupců do existující.

  • Neexistuje také žádné riziko, že pro určitý podtyp bude nastaven nevhodný atribut, například vehicle_reg_no pole pro politiku nemovitostí.

  • Není potřeba type atribut jako u metody jedné tabulky. Typ je nyní definován metadaty:názvem tabulky.

Tento model má však také několik nevýhod:

  • Společné atributy jsou smíchány s atributy specifickými pro podtyp a neexistuje snadný způsob, jak je identifikovat. Databáze to také nebude vědět.

  • Při definování tabulek byste museli opakovat společné atributy pro každou tabulku podtypu. To rozhodně není SUCHÉ.

  • Hledání všech zásad bez ohledu na podtyp je obtížné a vyžadovalo by to spoustu UNION s.

Takto byste se museli dotazovat na všechny zásady bez ohledu na typ:

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;

Všimněte si, že přidání nových podtypů by vyžadovalo úpravu výše uvedeného dotazu pomocí dalšího UNION ALL pro každý podtyp. To může snadno vést k chybám ve vaší aplikaci, pokud je tato operace zapomenuta.

Dědičnost tabulky tříd (neboli dědění tabulky podle typu):

Toto je řešení, které @David zmiňuje v druhé odpovědi. Vytvoříte jednu tabulku pro svou základní třídu, která obsahuje všechny běžné atributy. Pak byste pro každý podtyp vytvořili specifické tabulky, jejichž primární klíč zároveň slouží jako cizí klíč k základní tabulce. Příklad:

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)
);

Toto řešení řeší problémy identifikované v dalších dvou návrzích:

  • Povinné atributy lze vynutit pomocí NOT NULL .

  • Přidání nového podtypu vyžaduje přidání nové tabulky namísto přidávání sloupců do existující.

  • Žádné riziko, že pro určitý podtyp bude nastaven nevhodný atribut.

  • Není potřeba type atribut.

  • Nyní se již běžné atributy nemíchají se specifickými atributy podtypu.

  • Konečně můžeme zůstat V SUCHU. Při vytváření tabulek není potřeba opakovat společné atributy pro každý podtyp tabulky.

  • Správa automatického zvyšování id protože zásady se stávají jednodušší, protože to může být řešeno základní tabulkou, místo aby je každá tabulka podtypů generovala nezávisle.

  • Hledání všech politik bez ohledu na podtyp je nyní velmi snadné:Žádné UNION je potřeba - stačí SELECT * FROM policies .

Ve většině situací považuji za nejvhodnější přístup podle tabulky tříd.

Názvy těchto tří modelů pocházejí z knihy Martina Fowlera Patterns of Enterprise Application Architecture.



  1. Kdy/proč používat kaskádování v SQL Server?

  2. Logický pohled na datový model v R12.2

  3. Odeberte propojený server v SQL Server pomocí T-SQL

  4. Základy SQL Serveru Příkaz ALTER TABLE