pin*_* af 2 sql postgresql database-design many-to-many foreign-keys
我正在尝试简化数据库结构,我有两个表matches和team_statistics:
在这里,在team_statistics表中team_statistics.team_id应该是一个外键引用matches.teams_id和matches.teams_id1,同样team_statistics.group_id应该是一个外键引用matches.groups_id和matches.groups_id1
如何在PostgreSQL中执行此操作?
如果存在具有与另一个表这样做的其他方式matches和team_statistics我开放的建议,但我仍想知道如何有一个外键引用两个主键.
要回答标题和文字末尾的问题:
"我仍然想知道如何让一个外键引用两个主键."
这不可能.
一个FOREIGN KEY约束只能指向一个表,每个表只能有一个 PRIMARY KEY约束.
或者,您可以对引用每个(不同)表之一的相同列具有多个 FOREIGN KEY约束.(很少用.) PRIMARY KEY
但是,单个PK或FK 可以跨越多个列.
并且FK可以引用目标中任何明确定义的唯一(一组)列,而不仅仅是PK.手册:
外键必须引用作为主键或形成唯一约束的列.
多列PK或UNIQUE约束只能由具有匹配列类型的多列FK约束引用.
由于不允许在a UNIQUE或PRIMARY KEY约束的列列表中多次使用同一列,因此a 的目标列表FOREIGN KEY也不能多次使用同一列.但是没有什么可以阻止我们在源列表中多次使用同一列.这有可能实现你所要求的(但可能并不意味着):
"在team_statistics表中team_statistics.team_id应该是引用的外键matches.team_id和matches.team_id1"
需要定义(team_id, team_id1)表中的组合.值将仅限于表中作为逻辑结果的情况:matchesUNIQUEteam_statistics.team_idteam = team1matches
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);Run Code Online (Sandbox Code Playgroud)
甚至可能对某些设置有意义,但不是你的设置.
我有根据的猜测是你想要这样的东西:
(match_id, team_id)in table team_statistics应该是引用其中一个 (match_id, team_id) 或 (match_id, team_id1)在表中的外键matches.
这对于FK约束和两个表是不可能的.你可以CHECK使用假IMMUTABLE函数滥用约束并制作它NOT VALID.请参阅本答案中的"带有CHECK约束的更便宜"一章:
但那是先进的技巧,而且不太可靠.这不是我的建议,所以我不打算详细说明.我建议以有用的方式规范化您的架构,例如:
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)
);
Run Code Online (Sandbox Code Playgroud)
home标志着比赛的主队,但是,通过包含在PK中,每场比赛还限制最多两支球队.(PK列是NOT NULL隐式定义的.)
可选UNIQUE约束(team_id, match_id)可防止团队对抗自己.通过使用索引列的反转序列(与强制执行规则无关),这也提供了与PK互补的索引,这通常也是有用的.看到:
你可以添加一个单独的match_team_statistics,但这只是match_team现在的可选1:1扩展.或者只需添加列match_team.
我可能会为典型的显示添加视图,例如:
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;
Run Code Online (Sandbox Code Playgroud)
基本建议: