PostgreSQL:表只引用复合主键的一部分

6

我正在使用Postgres 9.6.2创建一个电影和电视节目流媒体服务数据库(为学校项目)。但是,我遇到了以下错误:

对于参考表“watchedepisodes”,没有匹配给定键的唯一约束条件

下面的TVratings表将接受一个电视节目,只要用户观看了至少一集(出现在WatchedEpisodes表中),并允许用户对其进行评分。由于WatchedEpisodes具有用户ID、电视节目ID、季节和剧集的复合主键,因此它不允许我仅从该表引用仅由uid和tid组成的复合键。

CREATE TABLE WatchedEpisodes (
  uid int unique references Users(uid),
  tid int,
  season int,
  episode int,
  FOREIGN KEY(tid, season, episode) REFERENCES Episodes(tid, season, episode),
  PRIMARY KEY (uid, tid, season, episode)
);

CREATE TABLE TVRatings (
  uid int,
  tid int,
  rating int check (rating > 0 and rating < 6),
  FOREIGN KEY(uid, tid) REFERENCES WatchedEpisodes(uid,tid),
  PRIMARY KEY(uid, tid)
);

想知道是否有一种方法只引用复合键的部分。这些只是我的两个表之一,如果需要更多信息,我可以添加更多。

1个回答

1

这实际上在规范中,但尚未实现。它被称为MATCH PARTIAL

CREATE TABLE foo (
  a int,
  b int,
  c int,
  PRIMARY KEY (a,b,c)
);
CREATE TABLE bar (
  a int,
  b int,
  FOREIGN KEY (a,b) REFERENCES foo (a,b) MATCH PARTIAL
);

你可以在文档中查看它的详细说明,

插入到引用列中的值与参考表和参考列的值使用给定的匹配类型进行匹配。有三种匹配类型:MATCH FULL、MATCH PARTIAL 和 MATCH SIMPLE(默认)。MATCH FULL 不允许多列外键的一个列为空,除非所有外键列都为空;如果它们都为空,则该行不需要在参考表中有匹配项。MATCH SIMPLE 允许任何外键列为空;如果它们中的任意一个为空,则该行不需要在参考表中有匹配项。MATCH PARTIAL 尚未实现。(当然,可以对引用列应用 NOT NULL 约束以防止出现这些情况。)

我认为目前它被视为反特性,因此不太可能很快就推出。

作为解决方法,您可以创建另一个仅包含 (a,b) 的表。

CREATE TABLE baz (
  a int,
  b int,
  PRIMARY KEY (a,b)
);

从这里你可以将两个表格链接起来...

CREATE TABLE foo (
  a int,
  b int,
  c int,
  PRIMARY KEY (a,b,c),
  FOREIGN KEY (a,b) REFERENCES baz
);
CREATE TABLE bar (
  a int,
  b int,
  FOREIGN KEY (a,b) REFERENCES baz
);

如果我无法进行部分匹配,您知道我可以采取另一种方法来解决这个问题吗? - Hannah Riedman
1
@HannahRiedman 已更新。如果这个答案对您有用,请考虑将其标记为已选择,并标记问题以移动到 [dba.se],那里可能更适合它。;) - Evan Carroll

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接