【问题标题】:How to reference a composite primary key in SQL如何在 SQL 中引用复合主键
【发布时间】:2017-09-28 08:37:07
【问题描述】:

我使用以下代码创建了以下 3 个表。

CREATE TABLE BUILDING(
BUILDINGNO CHAR(2),
BUILDINGWING VARCHAR2(15),
BUILDINGLANE VARCHAR2(15),
CONSTRAINT BUILDING_PK PRIMARY KEY(BUILDINGNO));

CREATE TABLE ROOM(
BUILDINGNO CHAR(2),
ROOMNO CHAR(2),
ROOMCAPACITY NUMBER(3),
CONSTRAINT ROOM_PK PRIMARY KEY(BUILDINGNO,ROOMNO),
CONSTRAINT ROOM_FK1 FOREIGN KEY(BUILDINGNO) REFERENCES BUILDING(BUILDINGNO));

CREATE TABLE SPEAKER(
SPEAKERID CHAR(2),
SPEAKERNAME VARCHAR2(20),
SPEAKERADDRESS VARCHAR2(50),
SPEAKERPHONE CHAR(12),
CONSTRAINT SPEAKER_PK PRIMARY KEY(SPEAKERID));

我需要创建的第四张表是这样的。

CREATE TABLE CONFERENCESESSION(
SESSIONID CHAR(4),
BUILDINGNO CHAR(2),
ROOMNO CHAR(2),
SPEAKERID CHAR(2),
SESSIONDATE DATE,
SESSIONPRICE NUMBER(4,2),
CONSTRAINT SESSION_PK PRIMARY KEY(SESSIONID),
CONSTRAINT SESSION_FK1 FOREIGN KEY(BUILDINGNO) REFERENCES BUILDING(BUILDINGNO),
CONSTRAINT SESSION_FK2 FOREIGN KEY(ROOMNO) REFERENCES ROOM(ROOMNO),
CONSTRAINT SESSION_FK3 FOREIGN KEY(SPEAKERID) REFERENCES SPEAKER(SPEAKERID));

但是我知道 FK2 ROOMNO(倒数第二行)的约束不正确,因为 ROOM 表中的 PK 是 BUILDINGNO,ROOMNO。 该行使用的正确代码是什么?

【问题讨论】:

标签: sql oracle foreign-keys constraints composite-primary-key


【解决方案1】:

我们声明一个 SQL FK (FOREIGN KEY) 约束,表示列列表的子行值始终作为形成 SQL PK (PRIMARY KEY) 或 UNIQUE NOT NULL 的列列表的子行值出现在别处。只要其他声明尚未暗示它,就声明它。它必须引用声明的 SQL PK (PRIMARY KEY) 或 UNIQUE NOT NULL 中的列列表。因此,您必须在引用的表中声明这一点,即使 NOT NULL 和包含的更小的 PK 或 UNIQUE NOT NULL 已经暗示了这一点。

因此请注意,SQL PK 不一定是关系意义上的 PK,即唯一但不包含较小的唯一列集,即作为不包含较小超键的超键,即最小/不可约超键,即一个 CK(候选键)。

在这里,您可能需要将 buildingnoroomno FK 替换为一个,(buildingno, roomno)Room

CONSTRAINT SESSION_FK12
    FOREIGN KEY(BUILDINGNO,ROOMNO) REFERENCES ROOM(BUILDINGNO,ROOMNO)

可能适合您的表格的含义-实际上您没有给出,所以我们无法知道,我们只能猜测。例如,如果buildingno 可以在 Room 中声明为 PK 或 UNIQUE NOT NULL,当 roomno IS NOT NULL 实际上与并暗示 (buildingno, roomno) 可以声明为 PK 或 UNIQUE NOT NULL 时,可能是您的 FK 正确,但您的Room 声明不充分。

当列列表的子行值始终作为列列表的子行值出现在其他地方时,称为 IND(包含依赖)约束。无法在 SQL 中声明非 FK IND;我们必须通过触发器强制执行。这可能是您的设计所需要的。

您可以将 FK 从 buildingno 保留到 Building,但我建议的 FK 以及 Room 上的 buildingno 中的 FK 引用 Building 暗示了这一点。

referencing part of the composite primary key

【讨论】:

  • 如果我写成这样对吗:CONSTRAINT SESSION_FK2 FOREIGN KEY(ROOMNO) REFERENCES ROOM(ROOMNO,BUILDINGNO),
  • 不,因为一列子行值如何在其他地方显示为两列子行值? (我会编辑我的答案。)
  • 如果我有 CONSTRAINT SESSION_FK2 FOREIGN KEY(BUILDINGNO,ROOMNO) REFERENCES ROOM(BUILDINGNO,ROOMNO) 那么我可以删除 CONSTRAINT SESSION_FK1 FOREIGN KEY(BUILDINGNO) REFERENCES BUILDING(BUILDINGNO),对吗?跨度>
  • 是的,我编辑的问题在最后一段中已经说过了。 (假设 PK 和 FK 是正确的。)这就是为什么第一句话说声明“当其他声明尚未暗示时”。
【解决方案2】:

正如我们在documentation 中看到的,我们可以创建复合外键:

CREATE TABLE CONFERENCESESSION ...
...
CONSTRAINT SESSION_FK2 
    FOREIGN KEY(BUILDINGNO, ROOMNO) 
    REFERENCES ROOM(BUILDINGNO, ROOMNO),
...

测试:

insert into building values (1, null, null);
insert into room values (1, 1, null);
insert into speaker (speakerid) values (1);
insert into conferencesession (sessionid,buildingno,roomno,speakerid) values (1, 1, 1, 1);
insert into conferencesession (sessionid,buildingno,roomno,speakerid) values (2, 1, 2, 1);

最后插入产生错误ORA-02291

【讨论】:

  • 这既没有说明也没有解释声明中的矛盾是什么,也没有解释解决问题的选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
  • 1970-01-01
  • 2014-05-25
  • 2012-03-21
相关资源
最近更新 更多