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 ettPRIMÄRNYCKEL
begränsning. -
Eller så kan du ha flera
UTLANDSNYCKEL
begränsningar på samma kolumn(er) som refererar till enPRIMÄ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: