Regels voor FK-beperkingen
Om de vraag in de titel en aan het einde van uw tekst te beantwoorden:
"Ik zou nog steeds graag willen weten hoe ik één externe sleutel kan hebben die verwijst naar twee primaire sleutels."
Dat is onmogelijk.
-
Een
FOREIGN KEY
beperking kan slechts naar één . verwijzen tafel en elke tafel kan slechts één . hebbenPRIMARY KEY
beperking. -
Of u kunt meerdere . hebben
FOREIGN KEY
beperkingen op dezelfde kolom(men) die verwijzen naar éénPRIMARY KEY
van elk een (andere) tafel. (Zelden nuttig.)
Echter , een enkele PK of FK kan beslaan meerdere kolommen.
En een FK kan verwijzen naar elke expliciet gedefinieerde unieke (set van) kolom(men) in het doel, niet alleen de PK. De handleiding:
Een PK met meerdere kolommen of UNIQUE
Er kan alleen naar een beperking worden verwezen door een FK-beperking met meerdere kolommen met overeenkomende kolomtypen.
Wat je vraagt
Aangezien het niet is toegestaan om dezelfde kolom meer dan één keer te gebruiken in de kolomlijst van een UNIQUE
of PRIMARY KEY
beperking, de doellijst van een FOREIGN KEY
kan dezelfde kolom ook niet meer dan één keer gebruiken. Maar er is niets dat ons ervan weerhoudt dezelfde kolom meer dan één keer te gebruiken in de bron lijst. Hierin ligt het potentieel om te implementeren wat je vraagt (maar waarschijnlijk niet de bedoeling was):
"In de team_statistics
tabel de team_statistics.team_id
moet een externe sleutel zijn die verwijst naar matches.team_id
en matches.team_id1
"
De combinatie van (team_id, team_id1)
in tabel matches
zou moeten worden gedefinieerd UNIQUE
. Waarden in team_statistics.team_id
zou beperkt zijn tot gevallen met team = team1
in tabel matches
als logisch gevolg:
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);
Misschien zelfs zinvol voor bepaalde instellingen, maar niet voor de jouwe.
Wat je waarschijnlijk nodig hebt
Mijn weloverwogen gok is dat je zoiets als dit wilt:
(match_id, team_id)
in tabel team_statistics
moet een externe sleutel zijn die verwijst naar ofwel (match_id, team_id)
of (match_id, team_id1)
in tabel matches
.
En dat is niet mogelijk met FK-beperkingen en slechts twee tabellen. Je zou misbruik maken van een CHECK
beperking met een nep IMMUTABLE
functie en maak deze NOT VALID
. Zie hoofdstuk "Goedkoper met een CHECK-beperking" in dit antwoord:
Maar dat is geavanceerde bedrog en minder betrouwbaar. Niet mijn suggestie hier, dus ik ga niet uitweiden. Ik stel voor om normaliseren uw schema op een nuttige manier, zoals:
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)
);
home
markeert het thuisteam van de wedstrijd, maar beperkt door opname in de PK ook tot max. twee teams per wedstrijd . (PK-kolommen zijn gedefinieerd NOT NULL
impliciet.)
De optionele UNIQUE
beperking op (team_id, match_id)
voorkomt dat teams tegen zichzelf spelen. Door de omgekeerde volgorde van indexkolommen te gebruiken (niet relevant voor het afdwingen van de regel) levert dit ook een index op die complementair is aan de PK, wat meestal ook nuttig is. Zie:
Je zou voeg een aparte match_team_statistics
toe , maar dat zou slechts een optionele 1:1-extensie zijn voor match_team
nu. U kunt ook gewoon kolommen toevoegen aan match_team
.
Ik zou weergaven kunnen toevoegen voor typische displays, zoals:
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;
Basisadvies: