【问题标题】:referencing part of the composite primary key引用复合主键的一部分
【发布时间】:2014-06-01 16:00:01
【问题描述】:

我在设置数据库表的引用时遇到问题。 我有以下结构:

CREATE TABLE club(
    id INTEGER NOT NULL,
    name_short VARCHAR(30),
    name_full VARCHAR(70) NOT NULL
);
CREATE UNIQUE INDEX club_uix ON club(id);
ALTER TABLE club ADD CONSTRAINT club_pk PRIMARY KEY (id);

CREATE TABLE team(
    id INTEGER NOT NULL,
    club_id INTEGER NOT NULL,
    team_name VARCHAR(30)
);
CREATE UNIQUE INDEX team_uix ON team(id, club_id);
ALTER TABLE team ADD CONSTRAINT team_pk PRIMARY KEY (id, club_id);
ALTER TABLE team ADD FOREIGN KEY (club_id) REFERENCES club(id);

CREATE TABLE person(
    id INTEGER NOT NULL,
    first_name VARCHAR(20),
    last_name VARCHAR(20) NOT NULL
);
CREATE UNIQUE INDEX person_uix ON person(id);
ALTER TABLE person ADD PRIMARY KEY (id);

CREATE TABLE contract(
    person_id INTEGER NOT NULL,
    club_id INTEGER NOT NULL,
    wage INTEGER
);
CREATE UNIQUE INDEX contract_uix on contract(person_id);
ALTER TABLE contract ADD CONSTRAINT contract_pk PRIMARY KEY (person_id);
ALTER TABLE contract ADD FOREIGN KEY (club_id) REFERENCES club(id);
ALTER TABLE contract ADD FOREIGN KEY (person_id) REFERENCES person(id);

CREATE TABLE player(
    person_id INTEGER NOT NULL,
    team_id INTEGER,
    height SMALLINT,
    weight SMALLINT

);
CREATE UNIQUE INDEX player_uix on player(person_id);
ALTER TABLE player ADD CONSTRAINT player_pk PRIMARY KEY (person_id);
ALTER TABLE player ADD FOREIGN KEY (person_id) REFERENCES person(id);
-- ALTER TABLE player ADD FOREIGN KEY (team_id) REFERENCES team(id); --this is not working

它给了我这个错误:

Error code -5529, SQL state 42529: a UNIQUE constraint does not exist on referenced columns: TEAM in statement [ALTER TABLE player ADD FOREIGN KEY (team_id) REFERENCES team(id)]

如您所见,team 表有复合主键(club_id + id),人通过合同引用俱乐部。 Person 对玩家和其他人员类型有一些共同的属性。

一个俱乐部可以拥有多支球队。雇员必须与俱乐部签订合同。球员(是个人的规格) - 如果使用 - 可以分配到俱乐部的一支球队。

有没有更好的方法来设计我的结构?我考虑过从团队的主键中排除 club_id,但我想知道这是否是唯一的方法。谢谢。

更新 1

我希望 id 仅作为俱乐部内部的团队标识,因此多个团队可以拥有相同的 id,只要它们属于不同的俱乐部。有可能吗?

更新 2 按照 philip 的建议更新了命名约定

为了更好地理解结构的一些业务规则:

  • 一个俱乐部可以有 1..n 支球队(主队、预备队、青年队 或 A 队、B 队...只有球队可以比赛,不能参加俱乐部)
  • 一支球队只属于一个俱乐部
  • 球员是一类人(其他类型(工作人员)是球探、教练等,因此他们不需要属于特定球队,如果受雇,只属于俱乐部)
  • 一个人可以与 1 个俱乐部签订 0..1 份合同(这意味着他有工作或失业)
  • 球员(如果受雇)属于俱乐部的一支球队

现在考虑一下 - 将 team_id 从球员转移到合同将解决我的问题,并且它可以满足“球员(如果受雇)属于俱乐部的一支球队”的条件,但对于其他工作人员类型来说这将是多余的。你怎么看?

【问题讨论】:

  • 是的,有更好的方法来设计你的结构。让team_id 成为team 的主键,最好是自动递增。我看不出为什么在不同的俱乐部会使用相同的team_id。如果有“club_team_id”,则将其设为不同的列。
  • 也许我可以利用这样的知识,在任何俱乐部中肯定有一支 id 为 0 的球队是主队,任何其他球队都可以是可选的,我认为没有理由让每支球队如果球队已经部分被俱乐部识别,则唯一 ID
  • 在问题中解释 team_id 的含义:一个唯一值标识球队(这是“id”的正确使用)或仅仅是球队内俱乐部。 (显然是后者。)数据库用户(包括问答者)需要知道这一点。
  • @Zavael 。 . .我认为您混淆了这些实体的实体和属性。对于外部观察者来说,俱乐部是球队的一个属性,俱乐部的球队编号系统也是如此。
  • @philip 是的,我应该,但我没有任何具体含义,只是试图通过重用其他关系来最小化表格列

标签: sql database-design ddl composite-primary-key


【解决方案1】:

当一个表中的子行必须是另一个(引用)表中的子行时,这就是包含依赖关系 (IND)。例如,玩家 team_id 引用团队 id(不是团队中的键)。当存在 IND 时,引用的子行是一个键,即外键 (FK)。例如,玩家 person_id 引用人员 ID(个人密钥)。在 SQL 中,一个 FOREIGN KEY 声明表示有一个 IND 并且引用的列是唯一的。 (即由 PRIMARY KEY 或 UNIQUE 声明)。 (所以它实际上意味着“外来超键”。)在 SQL 中,理想情况下,我们会通过 CHECK 约束声明一个 IND(当没有 FK 时)。 (但 DBMS 不能很好地支持 CHECK)。即检查 team_id 是否在团队中的玩家,该团队投影在 id 上。但是您试图声明一个 SQL FK。它失败了,因为正如错误消息所说,团队 ID 不是唯一的。


(请注意此处commented 与团队和他们的团队 ID 之间的区别。因为团队 ID 不能识别团队,所以您应该只说由团队 ID 和俱乐部识别的团队。OOP 必须区分 不仅在世界上的团队和世界上的团队ID(某种字符串)之间,而且还有编程语言的“team_id”指针/引用值。它是commented id" 是一个坏名字,因为单独的团队 id 并不能识别团队。我们可以直接使用世界上使用的术语。)

但您实际上想要比您的球员表 team_id IND 和 player_id FK 更强大的东西。即检查球员的 team_id 在俱乐部中与 club_id 配对,而 club_id 在合同中与 person_id 配对。

如果您的设计涉及 roster(club_id,team_id,player_id) 并且在 player 中没有 team_id 并且可能也没有合同,那么这些复杂的约束实际上是不必要的。

不,我们无法从“人通过合同引用俱乐部”的模式中“看到”。 (而且这个短语表达你的意思的方式很糟糕。)我们无法从表格和键中看出这一点。 每个表都包含满足某些由其列名参数化的语句的行;您必须给出这些声明。 例如,对于球员:人 [person_id] 效力于由 [team_id] 和某个俱乐部确定的球队。您还必须给出限制可能出现的情况的所有业务规则。例如:一个人最多可以签约一个俱乐部。一支球队至多属于一个俱乐部。没有语句,用户(也不是我们)无法使用数据库,没有语句和业务规则,您(也不是我们)无法确定约束。把它们写出来。

【讨论】:

  • 谢谢你的回答,我在理解第一段时有点挣扎,需要更多时间。不想讨厌,但你认为我在上次更新中提出的建议可能是一个好的步骤吗?
  • 感谢您向我展示了 CHECK 和 IND 之间的差异,对此我一无所知。我决定将 team_id 从球员转移到合同,并且知道我可以将 IND 提升为 FK :)
  • @Zavael 我希望您指的是 FK (=IND+key)、FS(=IND+superkey)、任意 IND 和任意约束之间的差异以及 SQL 中 FK for FS、CHECK for 之间的差异IND & CHECK 用于任意约束。 (是的,你的新设计是我的建议,但我的名单是你的合同。)
【解决方案2】:

团队表中的 team_id 列应该是唯一的。目前你所做的意味着一个teamid可以重复,只要它与不同的cluids一起使用,这是不正确的。

club 的 FK 已经处理了您提到的 0-n 关系。

编辑:继续处理关系问题。

由于一支球队可能只属于一个俱乐部,

  1. 该关系应由外键表示(club_id 指向俱乐部表)
  2. 主键不应包含 club_id

为什么?在主键中包含 club_id 意味着如果球队改变俱乐部,它会从根本上改变它是什么球队。除了我不明白为什么球队会改变俱乐部这一事实之外,如果真的发生了,球队将是完全一样的对象,完全独立于俱乐部。

否则将是一个可怕的概念错误。

【讨论】:

  • 感谢您的回答,是的,并且 club_id 已经是唯一的并且已编入索引,那么为什么将其用作标识符的一部分是不好的?我这样做没有优势吗?只要 team_id 属于不同的俱乐部,就会重复它,这很糟糕吗?
  • @Sebas 拥有 team_id 和俱乐部标识球队是完全合理的。他想要的并没有错。他错误地限制了它,特别是通过写一个无意义的声明[原文如此]。
  • @philip,我不同意你的看法。 team_id 根据定义是一个 ID。 ID 用于标识业务对象。他在 0.n 关系和 n.n 关系之间感到困惑。 n.n 关系确实必须由具有 team_idclub_id 列的表表示,每个列都是各自表的 FK [...]
  • @Zavael 这不是正常。一支球队可以属于不同的俱乐部吗?在这种情况下,除了 teamclub 表之外,您需要由另一个表表示的 n.n 关系。
  • @Sebas 他的编辑 1 说 team_id 加上俱乐部标识了一个团队。确实如此。正如球员号码加球队通常识别球员一样。世界上的一根弦。 12 英寸高的球衣。 你最多可以抱怨他违反了“id”的命名/术语约定。(正如我上面所说的。)
猜你喜欢
  • 1970-01-01
  • 2017-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
相关资源
最近更新 更多