I'm trying to simplify a database structure, and I have two tables matches
and team_statistics
:
Here in the team_statistics
table the team_statistics.team_id
should be a foreign key that references matches.team_id
and matches.team_id1
and similarly team_statistics.group_id
should be a foreign key referencing match.group_id
and match.group_id1
How to do this in PostgreSQL?
If there are other ways of doing this by having another table between matches
and team_statistics
I'm open for suggestion, but I would still like to know how to have one foreign key referencing two primary keys.
If I got your concept right, here is an example:
Rules for FK constraints
To answer the question in the title and at the end of your text:
"I would still like to know how to have one foreign key referencing two primary keys."
That's impossible.
A
FOREIGN KEY
constraint can only point to one table and each table can only have onePRIMARY KEY
constraint.Or you can have multiple
FOREIGN KEY
constraints on the same column(s) referencing onePRIMARY KEY
of a (different) table each. (Rarely useful.)However, a single PK or FK can span multiple columns.
And a FK can reference any explicitly defined unique (set of) column(s) in the target, not just the PK. The manual:
A multicolumn PK or
UNIQUE
constraint can only be referenced by a multicolumn FK constraint with matching column types.What you ask
Since it is not allowed to use the same column more than once in the column list of a
UNIQUE
orPRIMARY KEY
constraint, the target list of aFOREIGN KEY
can also not use the same column more than once. But there is nothing to keep us from using the same column more than once in the source list. Herein lies the potential to implement what you are asking (but probably did not mean to):"In the
team_statistics
table theteam_statistics.team_id
should be a foreign key that referencesmatches.team_id
andmatches.team_id1
"The combination of
(team_id, team_id1)
in tablematches
would need to be definedUNIQUE
. Values inteam_statistics.team_id
would be restricted to cases withteam = team1
in tablematches
as logical consequence:Might even make sense for certain setups, but not yours.
What you probably need
My educated guess is you want something like this:
(match_id, team_id)
in tableteam_statistics
should be a foreign key that references either(match_id, team_id)
or(match_id, team_id1)
in tablematches
.And that's not possible with FK constraints and just two tables. You could abuse a
CHECK
constraint with a fakeIMMUTABLE
function and make itNOT VALID
. See chapter "Cheaper with a CHECK constraint" in this answer:But that's advanced trickery and less reliable. Not my suggestion here, so I am not going to elaborate. I suggest to normalize your schema in a useful way, like:
home
marks the home team of the match but, by inclusion in the PK, also restricts to max two teams per match. (PK columns are definedNOT NULL
implicitly.)The optional
UNIQUE
constraint on(team_id, match_id)
prevents teams from playing against themselves. By using the inverted sequence of index columns (irrelevant for enforcing the rule) this also provides an index complementary to the PK, which is typically also useful. See:You could add a separate
match_team_statistics
, but that would just be an optional 1:1 extension tomatch_team
now. Alternatively just add columns tomatch_team
.I might add views for typical displays, like:
Basic advice:
I think you need to track teams to groups somewhere. Something like:
then you need the matches table to have two foreign keys against this. Then your statistics table should reference that as well.
You could aso create multiple foreign keys from team_statistics to matches but if you do this, you will run into an inability to grab statistics until a team is both on one side and the other side of a match.