【问题标题】:Creating a composite foreign key in SQL Server 2008在 SQL Server 2008 中创建复合外键
【发布时间】:2011-07-11 14:29:01
【问题描述】:

我有两个要为其创建外键的表。

主表

PK - Key1 - varchar(20)
PK - Key2 - date

辅助表

PK - AutoID
FK - Key1 - varchar(20)
FK - Key2 - date

当我尝试在主表和辅助表之间创建关系时,我不断收到消息

主表中的列不匹配主键或唯一 约束。

二级表中可能有很多条Key1和Key2相同的记录,所以我们将主键设为自动创建的数字。

关于如何设置这两个表之间的外键关系有什么想法吗?

【问题讨论】:

  • 主表上的Key1和Key2不是复合主键(或唯一约束)
  • Primary Table上的Key1和Key2设置为复合主键。
  • 您究竟想如何设置约束?

标签: sql sql-server-2008


【解决方案1】:

外键必须引用组成唯一索引(PK 或 UK)的列,具有相同的列数、类型和顺序。例如:

CREATE TABLE PrimaryTable (
  Key1 varchar(20),
  Key2 date)
GO

ALTER TABLE PrimaryTable ADD CONSTRAINT PK
  PRIMARY KEY (Key1, Key2)
GO

CREATE TABLE SecondaryTable (
  AutoID int IDENTITY,
  Key1 varchar(20),
  Key2 date)
GO

ALTER TABLE SecondaryTable ADD CONSTRAINT FK
  FOREIGN KEY (Key1, Key2) REFERENCES PrimaryTable (Key1, Key2)
GO

【讨论】:

  • 我今天被这个问题困扰了:引用键的顺序与表上声明的顺序不同。
  • 这里的问题与 TheKaptain 相同。引用的列必须与创建键的顺序相同。要获得正确的顺序,请右键单击外键(在 SSMS 中展开表时位于键文件夹下)并将脚本创建到剪贴板。粘贴。确保您引用的列与您的键的顺序相同。
【解决方案2】:

其中一些是重点,其中一些是其他人遇到此类问题的上下文(就像任何人实际上首先搜索?)

当您在创建键时遇到问题时,首先要检查的是确保您没有不匹配两个表中的数据类型。如果你在一个中有一个 bigint,另一个有一个 int,它会爆炸。这在所有键上都是正确的,但如果您使用多个字段,则更有可能出现。简单的数学说明了机会增加的原因。

下一个问题是数据。如果由于数据的原因无法创建key,则必须找出父表中不存在的子表中存在的内容。 LEFT JOIN 表(连接的第二/左侧的辅助)并且仅包括主表为空的行。您要么必须在父表中创建这些记录,要么将它们删除。

“解决”这个问题的一种方法是在父表上设置一个新的主键。然后,您在这个新的主键上创建一个外键,并在子表中匹配尽可能多的记录。然后,您设置了连接,您可以将清理作为辅助操作进行。

哪个更好?新的主键或使用复合键?这实际上取决于数据的性质,但我更喜欢使用派生键而不是自然键或复合键。但是,有时获取单个字段派生键所需的工作量很大。

【讨论】:

  • 我搜索并找到了这个答案,所以是的,有些人先搜索。 ;)
【解决方案3】:

这将起作用:

CREATE TABLE PTable (
     Key1 varchar(20) not null,
     Key2 date not null,
     constraint PK_PTable PRIMARY KEY (Key1,Key2)
)

CREATE TABLE STable (
     AutoID int IDENTITY(1,1) not null primary key,
     Key1 varchar(20) not null,
     Key2 date not null,
     constraint FK_STable_PTable FOREIGN KEY (Key1,Key2) references PTable (Key1,Key2)
)

您需要做的是让 Management Studio 为您的表格编写脚本并将它们与上述表格进行比较。

【讨论】:

    【解决方案4】:

    这里有一些很好的答案,但我想更进一步——为了后代。

    外键必须引用另一个表中的 Primary key(唯一,聚集索引)或 Unique 约束列。基本上,必要的组件是Unique 约束。我要补充一点,您可以在外键中包含可为空的列,但是如果您确实允许在“复合”键中使用空值,SQL 会跳过外键关系中数据的验证。这是要记住的重要一点,因为我们大多数人使用外键的主要原因是确保整个数据库的数据完整性。

    最后一点,我喜欢明确声明我所有的键名。为什么,你可能会问?如果您将来需要使用“全文索引”来获得更好的搜索功能,不这样做会强制您引用所有“自动生成”的键名。对于不需要数据转换或预定全文索引更新的小型项目,这可能没什么大不了的,但是如果您正在编写此功能的脚本,您可能会使您的工作变得更加困难(例如,必须查找您的 Primary 的实际名称密钥的默认名称:pk_someTable_1248594832828495904)。

    下面是我在编写 SQL 时会做的事情,以避免任何未来的陷阱:

    1. 如果可能,不要在复合外键上使用 NULL。
    2. 使用约定的命名约定明确命名键(例如PK_Schema/56_TalbeName_Col1_Col2)。这不仅为您提供了键的标准名称,而且您可以从索引中轻松查看引用了哪些列以及引用的顺序。

    代码:

    CREATE TABLE MySchema.PrimaryTable ( 
      Key1 varchar(20) NOT NULL, 
      Key2 date NOT NULL,
      CONSTRAINT PK_MySchema_PrimaryTable_Key1_Key2 PRIMARY KEY (Key1, Key2)
    )
    GO 
    
    CREATE TABLE MySchema.SecondaryTable ( 
      AutoID int IDENTITY, 
      Key1 varchar(20) NOT NULL, 
      Key2 date NOT NULL,
      CONSTRAINT FK_MySchema_SecondaryTable_Key1_Key2
         FOREIGN KEY (Key1, Key2) REFERENCES PrimaryTable (Key1, Key2)
    )
    GO 
    

    OptillectTeam 基本上对他的回答一无所知。我只是想澄清一些以前没有提到的重要事情。在 MSDN 视线中有一个很好的参考,讨论了这个以及更多关于外键的内容:Foreign Key Constraint

    【讨论】:

      【解决方案5】:

      在查询下方添加唯一键使用

         ALTER TABLE [TableName] ADD UNIQUE ([Column1], [Column2]);
      

      【讨论】:

        猜你喜欢
        • 2011-04-24
        • 1970-01-01
        • 1970-01-01
        • 2013-05-10
        • 2013-07-09
        • 2012-09-17
        • 2014-07-26
        • 2012-03-07
        相关资源
        最近更新 更多