sql >> Databasteknik >  >> RDS >> Sqlserver

Hur kan man representera arv i en databas?

@Bill Karwin beskriver tre arvsmodeller i sin SQL Antipatterns-bok, när han föreslår lösningar till SQL Entity-Attribute-Value-antimönster. Detta är en kort översikt:

Enkeltabellsarv (alias tabell per hierarkiarv):

Att använda ett enda bord som i ditt första alternativ är förmodligen den enklaste designen. Som du nämnde måste många attribut som är undertypsspecifika ges en NULL värde på rader där dessa attribut inte gäller. Med den här modellen skulle du ha en policytabell som skulle se ut ungefär så här:

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

Att hålla designen enkel är ett plus, men de största problemen med detta tillvägagångssätt är följande:

  • När det gäller att lägga till nya undertyper måste du ändra tabellen för att ta emot attributen som beskriver dessa nya objekt. Detta kan snabbt bli problematiskt när du har många undertyper, eller om du planerar att lägga till undertyper regelbundet.

  • Databasen kommer inte att kunna genomdriva vilka attribut som gäller och vilka som inte gör det, eftersom det inte finns någon metadata för att definiera vilka attribut som hör till vilka undertyper.

  • Du kan inte heller tvinga fram NOT NULL på attribut av en undertyp som bör vara obligatoriska. Du skulle behöva hantera detta i din ansökan, vilket i allmänhet inte är idealiskt.

Betongbordsarv:

Ett annat tillvägagångssätt för att ta itu med arv är att skapa en ny tabell för varje undertyp, och upprepa alla vanliga attribut i varje tabell. Till exempel:

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

Denna design kommer i princip att lösa de problem som identifierats för metoden med en tabell:

  • Obligatoriska attribut kan nu upprätthållas med NOT NULL .

  • Att lägga till en ny undertyp kräver att man lägger till en ny tabell istället för att lägga till kolumner i en befintlig.

  • Det finns heller ingen risk att ett olämpligt attribut ställs in för en viss undertyp, såsom vehicle_reg_no fält för en fastighetspolicy.

  • Det finns inget behov av type attribut som i enkeltabellmetoden. Typen definieras nu av metadata:tabellnamnet.

Men denna modell har också några nackdelar:

  • De vanliga attributen blandas med de undertypspecifika attributen, och det finns inget enkelt sätt att identifiera dem. Databasen kommer inte att veta det heller.

  • När du definierar tabellerna måste du upprepa de gemensamma attributen för varje undertypstabell. Det är definitivt inte torrt.

  • Att söka efter alla policyer oavsett undertyp blir svårt och skulle kräva en massa UNION s.

Så här måste du fråga alla policyer oavsett 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;

Observera att om du lägger till nya undertyper måste ovanstående fråga ändras med en ytterligare UNION ALL för varje undertyp. Detta kan lätt leda till buggar i din applikation om denna operation glöms bort.

Klasstabellsarv (alias tabell per typarv):

Det här är lösningen som @David nämner i det andra svaret. Du skapar en enda tabell för din basklass, som innehåller alla vanliga attribut. Sedan skulle du skapa specifika tabeller för varje undertyp, vars primärnyckel också fungerar som en främmande nyckel till bastabellen. Exempel:

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

Denna lösning löser problemen som identifierats i de andra två designerna:

  • Obligatoriska attribut kan upprätthållas med NOT NULL .

  • Att lägga till en ny undertyp kräver att man lägger till en ny tabell istället för att lägga till kolumner i en befintlig.

  • Ingen risk att ett olämpligt attribut ställs in för en viss undertyp.

  • Inget behov av type attribut.

  • Nu blandas inte de vanliga attributen med de undertypspecifika attributen längre.

  • Vi kan hålla oss TORRA, äntligen. Det finns inget behov av att upprepa de gemensamma attributen för varje undertypstabell när du skapar tabellerna.

  • Hantera ett automatiskt ökande id för policyerna blir enklare, eftersom detta kan hanteras av bastabellen, istället för att varje undertypstabell genererar dem oberoende.

  • Att söka efter alla policyer oavsett undertyp blir nu väldigt enkelt:Ingen UNION behövs - bara en SELECT * FROM policies .

Jag anser att klasstabellsmetoden är den mest lämpliga i de flesta situationer.

Namnen på dessa tre modeller kommer från Martin Fowlers bok Patterns of Enterprise Application Architecture.



  1. Använda spåra kausalitet för att förstå frågekörning

  2. Returnera en resultatuppsättning

  3. Rails, MySQL och Snow Leopard

  4. oracle systimestamp (sysdate) till millisekunder