当您没有所有列但可以通过另一个外键获取它们时,如何添加引用复合主键的外键?

How to add a foreign key referencing a composite primary key when you don't have all the columns, but can get them via another foreign key?

我有以下 tables:

create table AAA
(
    AAA_ID NUMBER
);

alter table AAA
    add constraint AAA_PK
    primary key (AAA_ID);

create table BBB
(
    BBB_ID NUMBER,
    AAA_ID NUMBER
);

alter table BBB
    add constraint BBB_PK
    primary key (BBB_ID, AAA_ID); --IMPORTANT

alter table BBB
    add constraint BBB_FK_01
    foreign key (AAA_ID)
    references AAA (AAA_ID);

create table CCC
(
    CCC_ID NUMBER,
    AAA_ID NUMBER
);

alter table CCC
    add constraint CCC_PK
    primary key (CCC_ID); --IMPORTANT

alter table CCC
    add constraint CCC_FK_01
    foreign key (AAA_ID)
    references AAA (AAA_ID);

create table CCC_BBB
(
    CCC_ID NUMBER,
    CCC_BBB_ID NUMBER,
    BBB_ID NUMBER
);

alter table CCC_BBB
    add constraint CCC_BBB_PK
    primary key (CCC_ID, CCC_BBB_ID);

alter table CCC_BBB
    add constraint CCC_BBB_FK_01
    foreign key (CCC_ID)
    references CCC (CCC_ID);

我想在引用 BBBCCC_BBB 中添加一个外键约束。 BBB_ID 直接出现在 CCC_BBB 中,但没有 AAA_ID。但是,AAA_ID 出现在 CCC 中,它被 CCC_BBB_FK_01 引用。是否可以在 SQL?

中表达此约束

我更喜欢符合标准的解决方案,但也欢迎特定于 Oracle 的解决方案。

编辑。我被要求澄清现实世界的问题是什么,所以这是我的尝试(我不想在这里讨论真正的问题领域):

AAA 是一个过程。 BBB 是一个过程步骤。多个进程具有名称相似但含义不同的步骤,因此 table 具有复合键。 CCC 是一个流程实例。他们的 ID 是唯一的,所以 table 没有复合 PK。 CCC_BBB 是在特定实例中采取的步骤列表。

我需要确保流程实例的步骤列表仅包括该流程允许的那些步骤。

您的问题似乎源于复合键应用不周。

让我们先从技术 non-composite 键开始。我稍微重命名了 table 和列名以增强可读性。主键是粗体。

  • A (A_ID, col1, col2, ...)
  • AB (AB_ID, A_ID, col1, col2, ...)
  • AC (AC_ID, A_ID, col1, col2, ...)
  • ABC (ABC_ID, AC_ID, AB_ID, col1, col2, ...)

这里有你描述的情况:AC和AB对A是children,ABC对AB和AC都是child,但是DBMS不能保证BC包含B和C 都属于同一个 A。这是纯基于 ID 的数据库设计中的一个 well-known 缺点;它无法保证 table 层次结构的一致性。

现在与复合键相同(这在自然键中很常见,但也适用于技术 ID):

  • A (A_ID, col1, col2, ...)
  • AB (A_ID, B_ID, col1, col2, ...)
  • AC (A_ID, C_ID, col1, col2, ...)
  • ABC (A_ID, B_ID, C_ID, col1, col2, ...)

这里保证了一致性,因为完整的parent键总是主键的一部分。

你正在做的是混合。您正在将复合键应用于最后一个 table,但在所有 parent table 中您都没有,所以为时已晚。您使用了 non-composite ID 概念并遇到了它的一致性问题。

  • A (A_ID, col1, col2, ...)
  • AB (AB_ID, A_ID, col1, col2, ...)
  • AC (AC_ID, A_ID, col1, col2, ...)
  • ABC (AC_ID, ACSUB_ID, AB_ID, col1, col2, ...)

您可以使用物化视图连接两个 table,然后将外键添加到此:

CREATE MATERIALIZED VIEW LOG ON CCC_BBB
   WITH SEQUENCE, ROWID(CCC_ID,CCC_BBB_ID,BBB_ID)
   INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW CCC_BBB_MV
   BUILD IMMEDIATE
   REFRESH FAST ON COMMIT
   AS SELECT CCC_ID,
             CCC_BBB_ID,
             BBB_ID,
             AAA_ID
      FROM   CCC_BBB b
             INNER JOIN
             CCC c
             ON ( b.CCC_ID = c.CCC_ID );

ALTER TABLE CCC_BBB_MV ADD CONSTRAINT ccc_bbb_mv__fk
  FOREIGN KEY ( AAA_ID, BBB_ID ) REFERENCES BBB ( AAA_ID, BBB_ID );

(以上代码未经测试,但应说明解决方案)

虽然它可能有效,但有点麻烦,您将使用更少的存储空间 space 将 AAA_ID 添加到您的 CCC_BBB table。