【问题标题】:Multiple Foreign Keys to multiple tables多个表的多个外键
【发布时间】:2013-02-28 18:20:12
【问题描述】:

我的数据库设计是这样的。简写形式:

CREATE TABLE LANDSLIDE (
      LNUMBER SERIAL NOT NULL,
      PRIMARY KEY (LNUMBER)
      ...

有 4 张桌子,例如(山体滑坡的一部分)

CREATE TABLE SCARP (
      SCPNUM CHAR(7) NOT NULL, 
      LNUMBER SMALLINT NOT NULL, 
      FOREIGN KEY (LNUMBER) REFERENCES LANDSLIDE (LNUMBER) ON DELETE CASCADE,
      ...
                   );

例如scpnum = scp0001

CREATE TABLE ACCUMULATION (
      ACCUNUM CHAR(8) NOT NULL,
      LNUMBER SMALLINT NOT NULL,
      FOREIGN KEY (LNUMBER) REFERENCES LANDSLIDE (LNUMBER) ON DELETE CASCADE,
      ...
                          );

例如accunum = accu0001

CREATE TABLE FRONT (
      FRNUM CHAR(6) NOT NULL,
      LNUMBER SMALLINT NOT NULL, 
      FOREIGN KEY (LNUMBER) REFERENCES LANDSLIDE (LNUMBER) ON DELETE CASCADE,
      ...
                    );

例如frnum = fr0001

CREATE TABLE OTHER (
      OTHERNUM CHAR(9) NOT NULL,
      LNUMBER SMALLINT NOT NULL,
      FOREIGN KEY (LNUMBER) REFERENCES LANDSLIDE (LNUMBER) ON DELETE CASCADE,
      ...
                   );

例如othernum = other0001

还有一张桌子,叫做材料(不同的石头,不同部位的土壤)。

CREATE TABLE MATERIAL (
     MATNUMBER VARCHAR(9) NOT NULL,
     ROCK,
     DISTRIBUTION,
     ...
     PRIMARY KEY(MATNUMBER,ROCK,DISTRIBUTION,...),
     CONSTRAINT material_matnumber_scarp_fkey FOREIGN KEY 
     (MATNUMBER) REFERENCES SCARP (SCPNUM) ON DELETE CASCADE,
     CONSTRAINT material_matnumber_accumulation_fkey FOREIGN KEY 
     (MATNUMBER) REFERENCES ACCUMULATION (ACCUNUM) ON DELETE CASCADE,
     CONSTRAINT material_matnumber_front_fkey FOREIGN KEY 
     (MATNUMBER) REFERENCES FRONT (FRNUM) ON DELETE CASCADE,
     CONSTRAINT material_matnumber_other_fkey FOREIGN KEY 
     (MATNUMBER) REFERENCES OTHER (OTHERNUM) ON DELETE CASCADE
                      );

当我向材料中插入数据时(在对其他表进行条目之后),它返回一个错误。 错误:在表“material”上插入或更新违反了外键约束“material_matnumber_accumulation_fkey” 详细信息:表“累积”中不存在键(matnumber)=(scp0001)

表格材质应如下所示:

MATNUMBER | ROCK | DISTRIBUTION | ...
----------+------+--------------+------
scp0001   |   A  |    lateral   | ...
scp0001   |   B  |    lateral   | ...
accu0001  |   B  |    central   | ...
scp0002   |   C  |    NULL      |
accu0002  |   A  |    lateral   |
fr0002    |   A  |    NULL      |
scp0003   |   B  |    cantral   |
accu0003  |   B  |    lateral   |
other0003 |   C  |    NULL      |

每个条目都是唯一的,因为 matnumber!

【问题讨论】:

  • 那么,ACCUMULATION 中是否有一行 ACCUNUM='scp0001'
  • 您尝试执行的操作不起作用。 matnumber scp0001 也必须存在于外键引用的所有表中,而不仅仅是SCRAP。您将必须创建多个列,每个外键一个列。您可以使用视图或其他东西将它们全部分组在一列中。
  • 我认为你的外键是向后的。
  • 阅读表继承
  • 检查我的回答你 FRONT 表不能容纳 scp0001 因为它最多只能容纳 scp000 char 6。

标签: sql postgresql foreign-keys


【解决方案1】:

如果我理解正确,这是一个可以通过超类型/子类型模式解决的常见问题。您还可以在 Material 表中有 4 个可为空的 FK 列,但这是我的建议:

CREATE TABLE Landslide  (                  --- no change here
      LNumber SERIAL NOT NULL,
      PRIMARY KEY (LNumber)
      ...

你说:“有 4 张桌子,就像(滑坡的一部分)”

因此,我们创建了一个额外的LandslidePart 表(这是我们的“超类型”表):

CREATE TABLE LandslidePart (
      PartType CHAR(1) NOT NULL, 
      PartNumber INT NOT NULL, 
      LNumber SMALLINT NOT NULL,
      PRIMARY KEY (PartType, PartNumber),
      CHECK (PartType IN ('S', 'A', 'F', 'O')),       --- the 4 subtypes
      FOREIGN KEY (LNumber) REFERENCES Landslide (LNumber) ON DELETE CASCADE,
      ...                                             --- other columns that are
                                                      --- common in all 4 tables
                   );

然后我们有 4 个(“子类型”)表,稍作改动:

CREATE TABLE Scarp (
      PartType CHAR(1) NOT NULL, 
      PartNumber INT NOT NULL, 
      PRIMARY KEY (PartType, PartNumber),
      CHECK (PartType = 'S'), 
      FOREIGN KEY (PartType, PartNumber) 
          REFERENCES LandslidePart (PartType, PartNumber) 
          ON DELETE CASCADE,
      ...                           --- columns that are related to Scarp
                   );

CREATE TABLE Accumulation (
      PartType CHAR(1) NOT NULL, 
      PartNumber INT NOT NULL, 
      PRIMARY KEY (PartType, PartNumber),
      CHECK (PartType = 'A'), 
      FOREIGN KEY (PartType, PartNumber) 
          REFERENCES LandslidePart (PartType, PartNumber) 
          ON DELETE CASCADE,
      ...                           --- columns that are related to Accumulation 
                   );

 --- We define in a similar way the other 2 tables: "Front" and "Other"

现在我们可以定义Material 表,它引用“超类型” (LandslidePart) 表,而不是四个表中的任何一个:

CREATE TABLE Material (
     PartType CHAR(1) NOT NULL, 
     MatNumber INT NOT NULL,
     Rock,
     Distribution,
     ...
     PRIMARY KEY(PartType, MatNumber, Rock, Distribution, ...),
     CONSTRAINT material_matnumber_landslidepart_fkey 
     FOREIGN KEY (PartType, MatNumber) 
         REFERENCES LandslidePart (PartType, PartNumber) 
         ON DELETE CASCADE,
                      );

【讨论】:

  • 哦,谢谢。这对我来说很清楚。我会试试这个!我可以创建其他表格,例如与零件具有相同关系的材料吗?比如另一个叫做 WATER 的。
  • 又是我。当我想选择滑坡的“陡坡”部分时,带有任何属性(如“形式”)我得到一个错误,即部分类型不明确。这个怎么查询??我是否必须将零件表中的零件类型重命名为唯一名称?
  • 您可以发布您使用的查询吗? (新问题就好了)
  • 我不记得使用 AS 别名引用列。所以我会先试试这个。对不起! =)
【解决方案2】:

检查您的外键长度和数据类型。

以下所有对MATNUMBER VARCHAR(9) NOT NULL的引用,在MATERIAL

SCPNUM CHAR(7) NOT NULL, *should be* SCPNUM VARCHAR(9) NOT NULL,
ACCUNUM CHAR(8) NOT NULL *should be* ACCUNUM VARCHAR(9) NOT NULL
FRNUM CHAR(6) NOT NULL, *should be* FRNUM VarCHAR(9) NOT NULL,

【讨论】:

  • Down voter 对不起,当密钥长度不匹配时,您如何级联? scp0001 不会在 FRONT 表中,因为 FRNUM 它只能容纳 scp000。
  • 很高兴知道为什么投反对票否则会认为它是酸葡萄
  • 我没有投反对票,但您真的认为这些更改会解决问题吗?有一列引用 4 个单独的表,具有明显不同的值是这里的问题(或者更好的是问题之一)。您的回答只会帮助 OP 通过CREATE TABLE 问题。但他根本无法插入任何行。
  • 是的,级联的使用方式将如此。给出的许多 OP 中的示例键都说“例如 fr0001”你确定外键不在表中吗?
  • ok @ypercube 刚刚从一个难题中解脱出来。自从我上次检查以来,似乎 OP 改变了一些重要元素。希望您的解决方案能够解决问题。祝你好运,放轻松。
猜你喜欢
  • 1970-01-01
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 2019-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多