sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur får man en främmande nyckel som pekar på två primärnycklar?

Regler för FK-begränsningar

För att svara på frågan i rubriken och i slutet av din text:

"Jag skulle fortfarande vilja veta hur man har en främmande nyckel som refererar till två primärnycklar."

Det är omöjligt.

  • En UTLANDSNYCKEL begränsning kan bara peka på en tabell och varje tabell kan bara ha ett PRIMÄRNYCKEL begränsning.

  • Eller så kan du ha flera UTLANDSNYCKEL begränsningar på samma kolumn(er) som refererar till en PRIMÄRNYCKEL av en (olika) tabell vardera. (Sällan användbart.)

Men , en enda PK eller FK kan spänner över flera kolumner.
Och en FK kan referera till vilken som helst explicit definierad unik (uppsättning av) kolumner i målet, inte bara PK. Manualen:

En PK med flera kolumner eller UNIK begränsning kan endast refereras av en FK-begränsning med flera kolumner med matchande kolumntyper.

Vad du frågar

Eftersom det inte är tillåtet att använda samma kolumn mer än en gång i kolumnlistan för en UNIQUE eller PRIMÄRNYCKEL constraint, mållistan för en FOREIGN KEY kan inte heller använda samma kolumn mer än en gång. Men det finns inget som hindrar oss från att använda samma kolumn mer än en gång i källan lista. Häri ligger potentialen att implementera det du frågar (men förmodligen inte menade):

"I team_statistics tabell team_statistics.team_id bör vara en främmande nyckel som refererar till matches.team_id och matches.team_id1 "

Kombinationen av (team_id, team_id1) i tabellen matches skulle behöva definieras UNIQUE . Värden i team_statistics.team_id skulle begränsas till fall med team =team1 i tabellen matches som logisk konsekvens:

ALTER TABLE matches
ADD constraint matches_teams_groups_uni UNIQUE (team_id, team_id1);

ALTER TABLE team_statistics
  ADD constraint team_statistics_team_group fkey
  FOREIGN KEY (team_id, team_id)  -- same column twice!
  REFERENCES matches(team_id, team_id1);

Kan till och med vara vettigt för vissa inställningar, men inte dina.

Vad du förmodligen behöver

Min kvalificerade gissning är att du vill ha något sånt här:

(match_id, team_id) i tabellen team_statistics bör vara en främmande nyckel som refererar till endera (match_id, team_id) eller (match_id, team_id1) i tabellen matches .

Och det är inte möjligt med FK-begränsningar och bara två bord. Du kunde missbruka en CHECK begränsning med en falsk IMMUTABLE funktion och gör den INTE GILTIG . Se kapitlet "Billigare med en CHECK-begränsning" i detta svar:

Men det är avancerat knep och mindre pålitligt. Inte mitt förslag här, så jag tänker inte utveckla det. Jag föreslår att du normaliserar ditt schema på ett användbart sätt, som:

CREATE TABLE team (team_id serial PRIMARY KEY
                 , team text NOT NULL UNIQUE);     -- add more attributes for team

CREATE TABLE match (match_id serial PRIMARY KEY);  -- add more attributes for match

CREATE TABLE match_team (
   match_id  int  REFERENCES match  -- short notation for FK
 , team_id   int  REFERENCES team
 , home boolean                     -- TRUE for home team, FALSE for away team
 , innings_score int
 -- more attributes of your original "team_statistics"
 , PRIMARY KEY (match_id, team_id, home)  -- !!! (1st column = match_id)
 , UNIQUE (team_id, match_id)             -- optional, (1st column = team_id)
);

hem markerar matchens hemmalag men, genom att inkluderas i PK, begränsar det också till max två lag per match . (PK-kolumner är definierade NOT NULL implicit.)

Den valfria UNIQUE begränsning på (team_id, match_id) hindrar lag från att spela mot sig själva. Genom att använda den inverterade sekvensen av indexkolumner (irrelevant för att upprätthålla regeln) tillhandahåller detta också ett index som är komplementärt till PK, vilket vanligtvis också är användbart. Se:

Du kunde lägg till en separat match_team_statistics , men det skulle bara vara ett valfritt 1:1-tillägg till match_team nu. Alternativt kan du bara lägga till kolumner i match_team .

Jag kanske lägger till vyer för typiska skärmar, som:

CREATE VIEW match_result AS
SELECT m.match_id
     , concat_ws(' : ', t1.team, t2.team) AS home_vs_away_team
     , concat_ws(' : ', mt1.innings_score, mt2.innings_score) AS result
FROM   match           m
LEFT   JOIN match_team mt1 ON mt1.match_id = m.match_id AND mt1.home
LEFT   JOIN team       t1  ON t1.team_id = mt1.team_id
LEFT   JOIN match_team mt2 ON mt2.match_id = m.match_id AND NOT mt2.home
LEFT   JOIN team       t2  ON t2.team_id = mt2.team_id;

Grundläggande råd:



  1. returnera nummer från mitten av en sträng med oregelbundet format

  2. SQL DELETE för nybörjare

  3. gör textkolumnen som unik nyckel

  4. SQL Server Management Studio – tips för att förbättra TSQL-kodningsprocessen