【问题标题】:Foreign Key Used in Composite Primary Key复合主键中使用的外键
【发布时间】:2021-04-04 17:11:26
【问题描述】:

是否可以使用复合外键作为表的复合主键的一部分?

例如,假设我有两个表:

CREATE TABLE DB.dbo.Partners
(
    CONSTRAINT pk_Partners_Id
    PRIMARY KEY (Name, City, State, Country, PostalCode),
    
    Name                VARCHAR(100)    NOT NULL,
    Address1            VARCHAR(100),   
    Address2            VARCHAR(100),   
    Address3            VARCHAR(100),   
    City                VARCHAR(150)    NOT NULL,   
    State               CHAR(2)         NOT NULL,   
    Country             CHAR(2)         NOT NULL,   
    PostalCode          VARCHAR(16)     NOT NULL,   
    Phone               VARCHAR(20),    
    Fax                 VARCHAR(20),    
    Email               VARCHAR(256)
)

...然后在第二个表中,我想在第二个表的主键中引用外键:

CREATE TABLE DB.dbo.PartnerContacts
(
    CONSTRAINT pk_PartnerContacts_Id
    PRIMARY KEY (fk_PartnerContacts_PartnerId, FirstName, LastName, PhoneNumber, Email),
                        
    CONSTRAINT fk_PartnerContacts_PartnerId
    FOREIGN KEY REFERENCES Partners(Name, City, State, Country, PostalCode),

    FirstName           VARCHAR(75)     NOT NULL,   
    MiddleName          VARCHAR(75),    
    LastName            VARCHAR(75)     NOT NULL,   
    PhoneNumber         VARCHAR(20)     NOT NULL,   
    MobileNumber        VARCHAR(20),    
    FaxNumber           VARCHAR(20),    
    Email               VARCHAR(256)    NOT NULL,   
    MailTo              VARCHAR(100),   
    Address1            VARCHAR(100),   
    Address2            VARCHAR(100),   
    Address3            VARCHAR(100),   
    City                VARCHAR(150),   
    State               CHAR(2),    
    Country             CHAR(2),    
    PostalCode          VARCHAR(16)
)

有什么办法可以做到吗?是的,在这些表中简单地使用 IDENTITY 列可能更容易,但如果我可以在没有 IDENTITY 的情况下定义实际关系,我想这样做。

编辑:

我想提供最终的、有效的 SQL。感谢所有回答的人!

CREATE TABLE DB.dbo.Partners
(
    CONSTRAINT pk_Partners_Id
    PRIMARY KEY (Name, City, State, Country, PostalCode),
    
    Id                  INT             NOT NULL   UNIQUE   IDENTITY(1, 1),
    Name                VARCHAR(100)    NOT NULL,
    Address1            VARCHAR(100),   
    Address2            VARCHAR(100),   
    Address3            VARCHAR(100),   
    City                VARCHAR(150)    NOT NULL,   
    State               CHAR(2)         NOT NULL,   
    Country             CHAR(2)         NOT NULL,   
    PostalCode          VARCHAR(16)     NOT NULL,   
    Phone               VARCHAR(20),    
    Fax                 VARCHAR(20),    
    Email               VARCHAR(256)
)

CREATE TABLE DB.dbo.PartnerContacts
(
    CONSTRAINT pk_PartnerContacts_Id
    PRIMARY KEY
    (PartnerId, FirstName, LastName, PhoneNumber, Email),
                        
    PartnerId           INT             NOT NULL CONSTRAINT fk_PartnerContacts_PartnerId FOREIGN KEY    REFERENCES Partners(Id),
    FirstName           VARCHAR(75)     NOT NULL,
    MiddleName          VARCHAR(75),    
    LastName            VARCHAR(75)     NOT NULL,   
    PhoneNumber         VARCHAR(20)     NOT NULL,   
    MobileNumber        VARCHAR(20),    
    FaxNumber           VARCHAR(20),    
    Email               VARCHAR(256)    NOT NULL,
    MailTo              VARCHAR(100),   
    Address1            VARCHAR(100),   
    Address2            VARCHAR(100),   
    Address3            VARCHAR(100),   
    City                VARCHAR(150),   
    State               CHAR(2),    
    Country             CHAR(2),    
    PostalCode          VARCHAR(16)
)

【问题讨论】:

  • 您尝试这样做时是否会出错?如果是这样,错误是什么?
  • Dylan:是:“外键中的引用列数与引用列数不同,表 'DB.dbo.PartnerContacts'”和“消息 1911,级别 16,状态 1,第 34 行列名称 'fk_PartnerContacts_PartnerId' 在目标表或视图中不存在。"
  • Name、City、State、Country、PostalCode 并不是我唯一依赖的东西,因此它作为主键是一个错误的选择。
  • 您说,“如果我可以在没有 IDENTITY 的情况下定义实际关系,我愿意这样做”。你被证明确实可以。然而,您选择在解决方案中使用 IDENTITY。令人困惑。

标签: sql foreign-keys primary-key


【解决方案1】:

您可能需要指定应该匹配的列。

CONSTRAINT fk_PartnerContacts_PartnerId
FOREIGN KEY         (columns that correspond to referenced columns) 
 REFERENCES Partners (Name, City, State, Country, PostalCode),

因此,您需要提供五个列名,其值应该与“合作伙伴”表中的 {Name, City, State, Country, PostalCode} 的值匹配。我很确定你不能用你目前的结构做到这一点。您将无法匹配“名称”。我认为您正在寻找类似的东西。

CREATE TABLE DB.dbo.PartnerContacts (
-- Start with columns that identify "Partner".
    partner_name VARCHAR(100) NOT NULL,
    partner_city VARCHAR(150) NOT NULL,
    partner_state CHAR(2) NOT NULL,
    partner_country CHAR(2) NOT NULL,
    partner_postcode VARCHAR(16) NOT NULL,
    CONSTRAINT fk_PartnerContacts_PartnerId
        FOREIGN KEY (partner_name, partner_city, partner_state, partner_country, partner_postcode) 
        REFERENCES Partners (Name, City, State, Country, PostalCode),
    FirstName    VARCHAR(75) NOT NULL,
    MiddleName   VARCHAR(75),
    LastName     VARCHAR(75) NOT NULL,
    PhoneNumber  VARCHAR(20) NOT NULL,
    MobileNumber VARCHAR(20),
    FaxNumber    VARCHAR(20),
    Email        VARCHAR(256) NOT NULL,
    MailTo       VARCHAR(100),
    Address1     VARCHAR(100),
    Address2     VARCHAR(100),
    Address3     VARCHAR(100),
    City         VARCHAR(150),
    State        CHAR(2),
    Country      CHAR(2),
    PostalCode   VARCHAR(16),
    CONSTRAINT pk_PartnerContacts_Id
    PRIMARY KEY (partner_name, partner_city, partner_state, partner_country, partner_postcode, 
                 FirstName, LastName, PhoneNumber, Email)
);

【讨论】:

  • 啊好吧,听起来我需要在 Partners 表中使用 IDENTITY 列并在 PartnerContacts 表中引用它。谢谢:)
  • 可能,但请确保 IDENTITY 标识的是合作伙伴,而不是一行。见stackoverflow.com/questions/7639637/…
【解决方案2】:

是的,这是可能的,并且通常被认为是最佳的数据库设计实践,但实际上,ID 列更容易处理。想想连接表,它们的主键是两个外键的组合。使用多个外键作为复合主键的一部分没有区别。

【讨论】:

  • 好的,这是个好消息……你能提供一个语法示例吗?
【解决方案3】:

是的,这绝对是可能的。我们确实有这样的例子,我们有一个复合外键,它是其他表的复合主键的一部分。

让我们稍微简化一下下面示例的用例。

假设我们有一个包含复合主键 (A, B) 的表 test1

现在我们可以有一个表,说 test2 具有主键 (P, Q, R),其中 test2 的 (P,Q) 引用 test1 的 (A,B)。

我在 MySql 数据库中运行了以下脚本,它运行良好。

CREATE TABLE `test1` (
`A` INT NOT NULL,
`B` VARCHAR(2) NOT NULL,
`C` DATETIME NULL,
`D` VARCHAR(45) NULL,
PRIMARY KEY (`A`, `B`));


CREATE TABLE `test2` (
`P` INT NOT NULL,
`Q` VARCHAR(2) NOT NULL,
`R` INT NOT NULL,
`S` DATETIME NULL,
`T` VARCHAR(8) NULL,
PRIMARY KEY (`P`, `Q`, `R`),
INDEX `PQ_idx` (`P`,`Q` ASC),
CONSTRAINT `PQ`
  FOREIGN KEY (`P`, `Q`)
  REFERENCES `test1` (`A`,`B`)
  ON DELETE CASCADE
  ON UPDATE CASCADE);

在上述情况下,数据库期望 (A,B) 的组合是唯一的,并且它是 test1 表中的主键。


但是,如果您尝试执行以下操作,脚本将会失败。数据库不允许您创建 test2 表。

CREATE TABLE `test2` (
`P` INT NOT NULL,
`Q` VARCHAR(2) NULL,
`R` DATETIME NULL,
`S` VARCHAR(8) NULL,
`T` VARCHAR(45) NULL,
  INDEX `P_idx` (`P` ASC),
  INDEX `Q_idx` (`Q` ASC),
  CONSTRAINT `P`
    FOREIGN KEY (`P`)
    REFERENCES `test1` (`A`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `Q`
    FOREIGN KEY (`Q`)
    REFERENCES `test1` (`B`)
    ON DELETE CASCADE
    ON UPDATE CASCADE);

在上述情况下,数据库期望 A 列单独唯一,B 列也是如此。(A,B) 的组合是否唯一无关紧要。

【讨论】:

    猜你喜欢
    • 2022-11-21
    • 1970-01-01
    • 2018-04-07
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 2012-05-20
    • 1970-01-01
    • 2017-08-06
    相关资源
    最近更新 更多