Règles pour les contraintes FK
Pour répondre à la question dans le titre et à la fin de votre texte :
"J'aimerais quand même savoir comment avoir une clé étrangère référençant deux clés primaires."
C'est impossible.
-
Une
FOREIGN KEY
la contrainte ne peut pointer que vers une table et chaque table ne peut en avoir qu'unePRIMARY KEY
contrainte. -
Ou vous pouvez en avoir plusieurs
FOREIGN KEY
contraintes sur la ou les mêmes colonnes faisant référence à unePRIMARY KEY
d'une table (différente) chacun. (Rarement utile.)
Cependant , un seul PK ou FK peut s'étendre sur plusieurs colonnes.
Et un FK peut faire référence à n'importe quel (ensemble de) colonne(s) unique(s) explicitement défini(s) dans la cible, pas seulement le PK. Le manuel :
Une PK multicolonne ou UNIQUE
La contrainte ne peut être référencée que par une contrainte FK multicolonne avec des types de colonne correspondants.
Ce que vous demandez
Puisqu'il n'est pas permis d'utiliser la même colonne plus d'une fois dans la liste des colonnes d'un UNIQUE
ou PRIMARY KEY
contrainte, la liste cible d'une FOREIGN KEY
ne peut pas non plus utiliser la même colonne plus d'une fois. Mais rien ne nous empêche d'utiliser la même colonne plus d'une fois dans la source liste. C'est là que réside la possibilité de mettre en œuvre ce que vous demandez (mais que vous n'avez probablement pas voulu) :
"Dans les team_statistics
tablez le team_statistics.team_id
doit être une clé étrangère faisant référence à matches.team_id
et matches.team_id1
"
La combinaison de (team_id, team_id1)
dans le tableau matches
devra être défini UNIQUE
. Valeurs dans team_statistics.team_id
serait limité aux cas avec team = team1
dans le tableau matches
comme conséquence logique :
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);
Peut-être même logique pour certaines configurations, mais pas la vôtre.
Ce dont vous avez probablement besoin
Ma supposition éclairée est que vous voulez quelque chose comme ça :
(match_id, team_id)
dans le tableau team_statistics
doit être une clé étrangère qui fait référence à soit (match_id, team_id)
ou (match_id, team_id1)
dans le tableau matches
.
Et ce n'est pas possible avec les contraintes FK et seulement deux tables. Vous pourriez abuser d'un CHECK
contrainte avec un faux IMMUTABLE
fonction et rendez-la NOT VALID
. Voir le chapitre "Moins cher avec une contrainte CHECK" dans cette réponse :
Mais c'est une supercherie avancée et moins fiable. Ce n'est pas ma suggestion ici, donc je ne vais pas élaborer. Je suggère de normaliser votre schéma d'une manière utile, comme :
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
marque l'équipe à domicile du match mais, par inclusion dans le PK, limite également à deux équipes maximum par match . (Les colonnes PK sont définies NOT NULL
implicitement.)
L'option UNIQUE
contrainte sur (team_id, match_id)
empêche les équipes de jouer contre elles-mêmes. En utilisant la séquence inversée des colonnes d'index (non pertinente pour l'application de la règle), cela fournit également un index complémentaire au PK, ce qui est généralement également utile. Voir :
Vous pourriez ajouter un match_team_statistics
séparé , mais ce ne serait qu'une extension facultative 1:1 de match_team
à présent. Sinon, ajoutez simplement des colonnes à match_team
.
Je pourrais ajouter des vues pour les affichages typiques, comme :
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;
Conseil de base :