允许在没有值的情况下创建外键,但在更新或添加时强制不为null

时间:2015-04-15 04:13:37

标签: sql sql-server foreign-keys nullable

我需要在表中添加一个外键。

随着每条记录的修改,用户最终会添加列值。

所以我创建了一个FK约束with NOCHECK。但该列不能为空,因此我将其声明为NOT NULL。 SQL Server不允许我在可以为空的列上执行此操作,它必须具有值或默认值。

如何创建一个首先没有条目但是应该修改的FK必须提供密钥值?

2 个答案:

答案 0 :(得分:1)

听起来你有一个可选的关系 - 将FK建模为NULLable,同时仍然强制执行约束是一种常见的方法(NDB FK' s将不会被RDBMS检查)。例如在下面,我们有一个Person表,但最初在Person捕获期间,我们不知道用户所在的城市,所以我们使CityId外键可以为空:

CREATE TABLE City
(
   CityId INT NOT NULL PRIMARY KEY,
   Name NVARCHAR(200)
);

CREATE TABLE Person
(
   PersonId INT NOT NULL PRIMARY KEY,
   CityId INT NULL, -- Nullable
   Name NVARCHAR(200),

   CONSTRAINT FK_PersonCity FOREIGN KEY(CityID) REFERENCES City(CityID)
);

Person现在允许CityID为NULL(表示未知),或者如果为非null,则CityID必须有效且存在于City中。唯一的问题是'这里是你需要LEFT OUTER JOIN人回城去考虑城市未知的人。

我见过的另一个策略是在主表中添加DUMMY行(例如City(ID = 0, Name = 'Unknown'),然后将其用作外键的默认值 - 它将保证INNER JOIN。< / p>

如果您需要强制要求在以后的步骤中外键(城市分类)成为强制性要求,我建议您在业务逻辑中执行此操作 - 在代码中或从存储过程中执行此操作。

答案 1 :(得分:0)

将列添加到现有表时,将使用NULL值创建新列。因此,除非您还指定了默认值,否则无法向表中添加not null列。在这种情况下,新字段将包含默认值。

如果您想添加一个强制性FK的新列,您实际上只有两个选项:

  • 将列创建为可为空,等待所有字段都填满,然后将列的定义更改为not null
  • 将列创建为可为空,执行更新,使用正确的值填充字段,然后将列的定义更改为not null

第一个选项的优点是你不会长时间持有桌子上的锁。缺点是可能需要数周或数月才能最终填满每一行。

第二个选项的优点是可以非常快速地创建和填充该字段,并且所有字段都可以放在一个事务中。缺点是您在整个表中锁定持续时间。首先获取锁定可能非常困难,而且您的DBA可能会有几个关于锁定它的选择词超过几秒钟。

获取上述DBA并确定哪种方式最适合您的特定情况。