【问题标题】:Error Defining Foreign Key定义外键时出错
【发布时间】:2014-02-16 17:11:14
【问题描述】:

我定义了以下两个数据库表:

CREATE TABLE [dbo].[Classrooms] (
  [ID]               INT          IDENTITY (1, 1) NOT NULL,
  [SystemAccount_ID] INT          NOT NULL,
  [ClassroomName]    VARCHAR (30) NOT NULL,
  CONSTRAINT [PK_Table] PRIMARY KEY CLUSTERED ([ID]),
  CONSTRAINT [FK_Classrooms_SystemAccount] FOREIGN KEY ([SystemAccount_ID]) REFERENCES [dbo].[SystemAccounts] ([ID])
);

CREATE TABLE [dbo].[Students] (
   [ID]               INT          IDENTITY (1, 1) NOT NULL,
   [SystemAccount_ID] INT          NOT NULL,
   [Classroom_ID]     INT          NULL,
   [PhotoID]          INT          NULL,
   [FirstName]        VARCHAR (20) NOT NULL,
   [LastName]         VARCHAR (40) NOT NULL,
   [NewsTemplate]     TINYINT      NOT NULL,
   CONSTRAINT [PK_Students] PRIMARY KEY CLUSTERED ([ID] ASC),
   CONSTRAINT [FK_Students_Classrooms] FOREIGN KEY ([Classroom_ID]) REFERENCES [dbo].[Classrooms] ([ID]),
   CONSTRAINT [FK_Students_SystemAccounts] FOREIGN KEY ([SystemAccount_ID]) REFERENCES [dbo].[SystemAccounts] ([ID])
);

数据模型详情:

  • 学生通过Classroom_IDFK 属于零个或一个教室
  • 学生通过SystemAccount_IDFK 属于一个系统帐户
  • 教室通过SystemAccount_ID FK 属于一个系统帐户(意味着一个系统帐户可以有零个或多个教室)

我试图做的是在将学生添加到教室时(通过在学生表中设置 Classroom_ID 键)强制该教室属于与学生相同的系统帐户。我可以轻松地在业务逻辑层执行此操作,但随后我会要求每个程序员记住这样做。所以理想情况下,我可以在数据层执行此操作作为约束。

我尝试向 Student 表添加 FK 约束:

CONSTRAINT [FK_Students_ToTable] FOREIGN KEY ([SystemAccount_ID]) REFERENCES [Classrooms]([SystemAccount_ID])

这会导致 SQL Server 出现以下错误:

由于验证错误,更新无法继续。
请更正以下错误,然后重试。

SQL71516 :: 引用的表“[dbo].[Classrooms]”不包含与外键中的引用列列表匹配的主键或候选键。如果引用的列是计算列,它应该被持久化。

我尝试了几种不同的方法,但我的 SQL mojo 功能不足以破解这一点。任何帮助将不胜感激。

【问题讨论】:

  • 在 Classrooms.SystemAccount_ID ALTER TABLE Classrooms ADD CONSTRAINT constraintName UNIQUE (SystemAccount_ID)上添加唯一键
  • 您正在尝试创建一个引用 CLassrooms 中的 SystemAccount_ID 列的 FK,但这既不是该表的主键,也没有唯一的对该列的约束。 必须给出这两个条件之一,该列才能被外键约束引用!还是您想改为引用 Classrooms.ID 列?
  • @Mihai 我忽略了一个细节是系统帐户可以有零个或多个教室。我假设您建议的唯一约束将阻止我将多个教室分配给同一系统帐户。
  • @marc_s 感谢您的帮助。我认为唯一约束是 Classrooms.ID、Classrooms.SystemAccount_ID 的元组,因为 SystemAccount 可以有零个或多个教室。如果我在 Classrooms 中的 SystemAccount_ID 列上设置一个唯一约束,那么我假设每个系统帐户不能拥有一个以上的教室。对吗?
  • @OGHaza 感谢您的帮助。将此逻辑添加到存储过程时遇到的问题是,我遇到了与将此逻辑添加到业务层相同的问题。所有维护这个系统的开发者都需要知道这个秘密细节。如果可行,我真的想将其添加到 Check Constraint 或 FK Constraint 中。

标签: sql sql-server database foreign-keys data-integrity


【解决方案1】:

Classrooms中的两列组合上添加UNIQUE约束:

CREATE TABLE [dbo].[Classrooms] (
  [ID]               INT          IDENTITY (1, 1) NOT NULL,
  [SystemAccount_ID] INT          NOT NULL,
  [ClassroomName]    VARCHAR (30) NOT NULL,
  CONSTRAINT [PK_Table] 
    PRIMARY KEY CLUSTERED ([ID]),
  CONSTRAINT [FK_Classrooms_SystemAccount] 
    FOREIGN KEY ([SystemAccount_ID]) 
    REFERENCES [dbo].[SystemAccounts] ([ID]),
  CONSTRAINT [UQ_Classrooms_ID_SystemAccount_ID] 
    UNIQUE ([SystemAccount_ID], [ID])
);

然后,在Students 表中,将两个FOREIGN KEY 约束合并为一个,或者在您的情况下(因为Classroom_ID 可以为空),将FK 更改为Classroom 以使用两列的组合:

CREATE TABLE [dbo].[Students] (
  [ID]               INT          IDENTITY (1, 1) NOT NULL,
  [SystemAccount_ID] INT          NOT NULL,
  [Classroom_ID]     INT          NULL,
  [PhotoID]          INT          NULL,
  [FirstName]        VARCHAR (20) NOT NULL,
  [LastName]         VARCHAR (40) NOT NULL,
  [NewsTemplate]     TINYINT      NOT NULL,
  CONSTRAINT [PK_Students] 
    PRIMARY KEY CLUSTERED ([ID] ASC),
  CONSTRAINT [FK_Students_Classrooms] 
    FOREIGN KEY ([SystemAccount_ID], [Classroom_ID]) 
    REFERENCES [dbo].[Classrooms] ([SystemAccount_ID], [ID]),
  CONSTRAINT [FK_Students_SystemAccounts]         -- this wouldn't be needed if
    FOREIGN KEY ([SystemAccount_ID])              -- Classrooms_ID was NOT NULL
    REFERENCES [dbo].[SystemAccounts] ([ID])
);

【讨论】:

  • 我会试一试,并在我有机会回来时接受它作为答案。感谢您花时间帮助我。我很感激。
猜你喜欢
  • 1970-01-01
  • 2014-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
  • 2012-11-17
相关资源
最近更新 更多