一个在MySQL中有两个引用的字段

时间:2013-09-27 17:58:24

标签: mysql foreign-keys

我有三张桌子:

CREATE TABLE Address (
  ResidentID CHAR(5) NOT NULL,
  Location varchar(255) NOT NULL,
  KEY ResidentID(ResidentID)
);

CREATE TABLE Customer (
  CustomerID CHAR(5) NOT NULL,
  ContactName varchar(40) NOT NULL,
  PRIMARY KEY (CustomerID)
);

CREATE TABLE Supplier (
  SupplierID CHAR(5) NOT NULL,
  SupplierName varchar(40) NOT NULL,
  PRIMARY KEY (SupplierID)
);

我想使用外键将CustomerID和SupplierID存储在Address.ResidentID字段中:

ALTER TABLE Address ADD CONSTRAINT fk_CustomerID1 FOREIGN KEY(ResidentID) REFERENCES Customer(CustomerID);
ALTER TABLE Address ADD CONSTRAINT fk_SupplierID1 FOREIGN KEY(ResidentID) REFERENCES Supplier(SupplierID);

但第二个“ALTER TABLE”引发错误:关系已存在

有什么建议吗?

数据示例:

CustomerID  ContactName
C0001       Den

SupplierID  ContactName
S0001       John

So Address table should contains:

ResidentID  Location
C0001       Alaska
S0001       Nevada

2 个答案:

答案 0 :(得分:3)

您需要引用客户/供应商的地址(如果他们只有一个)或两个不同的列。

您在此SQLFiddle中看到的原因如果INSERT引用了两个表,则无法Address ResidentID表中所需的列。您只能插入与CustomerSupplier的内容相匹配的行,但您想要一个无法以这种方式创建的OR连接。

(注意:在我的解决方案中,我假设地址是可选的。由于Tom指出in the comments可能不是您想要的或预期的。确保在第一个标记FK列解决方案为NOT NULL如果您希望地址是强制性的,那么对于第二个地址则更复杂。那么您必须记住正确的插入顺序。)

或者:

CREATE TABLE Address (
  AddressID CHAR(5) NOT NULL,
  Location varchar(255) NOT NULL,
  PRIMARY KEY (AddressID)
);

CREATE TABLE Customer (
  CustomerID CHAR(5) NOT NULL,
  AddressID CHAR(5),
  ContactName varchar(40) NOT NULL,
  PRIMARY KEY (CustomerID)
);

CREATE TABLE Supplier (
  SupplierID CHAR(5) NOT NULL,
  AddressID CHAR(5),
  SupplierName varchar(40) NOT NULL,
  PRIMARY KEY (SupplierID)
);

ALTER TABLE Customer ADD CONSTRAINT fk_AddressID_Cust FOREIGN KEY(AddressID) REFERENCES Address(AddressID);
ALTER TABLE Supplier ADD CONSTRAINT fk_AddressID_Supp FOREIGN KEY(AddressID) REFERENCES Address(AddressID);

CREATE TABLE Address (
  CustomerID CHAR(5),
  SupplierID CHAR(5),
  Location varchar(255) NOT NULL,
  PRIMARY KEY (CustomerID, SupplierID)
);

CREATE TABLE Customer (
  CustomerID CHAR(5) NOT NULL,
  ContactName varchar(40) NOT NULL,
  PRIMARY KEY (CustomerID)
);

CREATE TABLE Supplier (
  SupplierID CHAR(5) NOT NULL,
  SupplierName varchar(40) NOT NULL,
  PRIMARY KEY (SupplierID)
);

ALTER TABLE Address ADD CONSTRAINT fk_CustomerID1 FOREIGN KEY(CustomerID) REFERENCES Customer(CustomerID);
ALTER TABLE Address ADD CONSTRAINT fk_SupplierID1 FOREIGN KEY(SupplierId) REFERENCES Supplier(SupplierID);

答案 1 :(得分:-1)

你正在尝试的方法是(a)不可能和(b)即使有可能也不受欢迎。

最好的方法是拥有一个CustomerAddress表和一个SupplierAddress表,每个表都有一个匹配基表的FK;或者如果必须,还有一个具有适当约束的交叉引用表。

如果您拥有单个地址表的动机是代码重用,您仍然可以这样做......根据模板xxxAddress表设计来思考,该表设计可以引用任何基础xxx表。您可以编写将基表名称视为参数的非数据库代码,然后随着时间的推移添加更多基表,可以处理任意数量的xxxAddress表。

或者,如果您拥有单个地址表的动机是为了简化报告,您始终可以创建一个视图或存储过程,它返回所有此类表的并集+一个添加的字段,以指示每个地址行的基表。 / p>

Angelo我根据你的意见修改了一下---

Angelo,我在本地MySQL实例(不是SQLFiddle)中运行了示例代码并发现了错误。

我很惊讶(你每天都学到一些东西)MySQL确实允许在同一个字段上定义两个外键约束;但是当您尝试插入数据时,在尝试将FK指向Customer表时,我收到一条错误,指出外键约束未能引用Supplier表;对于试图将FK指向供应商表格的插入,反之亦然。

所以我修改后的声明是(a)可以在至少一些DBMS中创建一个头脑中的FK - 在MySQL,MS SQL Server和Oracle中验证 - 尽管(b)这只有在使用时才有意义外键可以通过多个表中的ID引用相同的逻辑实体(例如,以确保在所有必需的表中存在相应的记录); (c)如果用于引用主键不是同一逻辑实体的多个表,只有在相同的主键值碰巧存在于所有引用表中时才起作用,这可能导致微妙,困难发现错误。

换句话说,只有在供应商ID = 3时才尝试插入引用客户ID = 3的记录时,您的示例才有效,这在逻辑上是无关的。

所以我稍微修改了对OP的回答是,当外键引用不同的ENTITIES时,您尝试做的事情是不可能的(或逻辑上的),如客户和供应商的OP示例中所示。