猿问
下载APP

非主键的外键

非主键的外键

我有一个保存数据的表,其中一行需要存在于另一个表中。所以,我想要一个外键来保持参照完整性。

CREATE TABLE table1(
   ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
   AnotherID INT NOT NULL,
   SomeData VARCHAR(100) NOT NULL)CREATE TABLE table2(
   ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
   AnotherID INT NOT NULL,
   MoreData VARCHAR(30) NOT NULL,

   CONSTRAINT fk_table2_table1 FOREIGN KEY (AnotherID) REFERENCES table1 (AnotherID))

但是,正如你所看到的,表我是外键,列不是PK。有没有办法创建这个外键,或者更好的方法来维护这种引用完整性?


慕标琳琳
浏览 74回答 3
3回答

春华秋衣

如果您确实要为非主键创建外键,则它必须是对其具有唯一约束的列。来自联机丛书:FOREIGN KEY约束不必仅链接到另一个表中的PRIMARY KEY约束; 它也可以定义为引用另一个表中UNIQUE约束的列。所以在你的情况下,如果你做出AnotherID独特的,它将被允许。如果你不能应用一个独特的约束你运气不好,但如果你考虑它,这确实有意义。虽然如前所述,如果你有一个非常好的主键作为候选键,为什么不使用它?

慕少森

正如其他人所指出的那样,理想情况下,外键将被创建为对主键(通常是IDENTITY列)的引用。但是,我们并不是生活在一个理想的世界中,有时甚至对模式的“小”改变也会对应用程序逻辑产生明显的连锁反应。考虑具有SSN列(和哑主键)的Customer表的情况,以及还包含SSN列的Claim表(由Customer数据中的业务逻辑填充,但不存在FK)。该设计存在缺陷,但已经使用了好几年,并且已经在架构上构建了三种不同的应用程序。显而易见的是,剥离Claim.SSN并建立真正的PK-FK关系将是理想的,但也将是一次重大的改革。另一方面,对Customer.SSN设置UNIQUE约束,并在Claim.SSN上添加FK,可以提供参照完整性,对应用程序影响很小或没有影响。不要误解我,我都是为了正常化,但有时候实用主义胜过理想主义。如果可以通过创可贴帮助平庸的设计,可以避免手术。

MYYA

Necromancing。我假设有人在这里登陆时,他需要一个包含非唯一键的表中的列的外键。&nbsp;问题是,如果遇到这个问题,数据库模式将被非规范化。例如,您可以将房间保存在一个表中,其中包含room-uid主键,DateFrom和DateTo字段,以及另一个uid,此处为RM_ApertureID,用于跟踪同一房间,以及一个软删除字段,如RM_Status,其中99表示“已删除”,<> 99表示“已激活”。因此,当您创建第一个房间时,您将RM_UID和RM_ApertureID作为与RM_UID相同的值插入。然后,当您将房间终止到某个日期,并使用新的日期范围重新建立它时,RM_UID是newid(),并且前一个条目中的RM_ApertureID将成为新的RM_ApertureID。因此,如果是这种情况,RM_ApertureID是一个非唯一字段,因此您无法在另一个表中设置外键。并且无法将外键设置为非唯一列/索引,例如在T_ZO_REM_AP_Raum_Reinigung中(WHERE RM_UID实际上是RM_ApertureID)。但是为了禁止无效值,你需要设置一个外键,否则,数据垃圾是结果而不是以后...现在你可以在这种情况下做的事情(没有重写整个应用程序)是插入一个CHECK约束,标量函数检查密钥的存在:IF&nbsp;&nbsp;EXISTS&nbsp;(SELECT&nbsp;*&nbsp;FROM&nbsp;sys.check_constraints&nbsp;WHERE&nbsp;object_id&nbsp;=&nbsp;OBJECT_ID(N'[dbo].[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]')&nbsp;AND&nbsp;parent_object_id&nbsp;=&nbsp;OBJECT_ID(N'[dbo].[T_ZO_REM_AP_Raum_Reinigung]'))ALTER&nbsp;TABLE&nbsp;dbo.T_ZO_REM_AP_Raum_Reinigung&nbsp;DROP&nbsp;CONSTRAINT&nbsp;[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]GOIF&nbsp;&nbsp;EXISTS&nbsp;(SELECT&nbsp;*&nbsp;FROM&nbsp;sys.objects&nbsp;WHERE&nbsp;object_id&nbsp;=&nbsp;OBJECT_ID(N'[dbo].[fu_Constaint_ValidRmApertureId]')&nbsp;AND&nbsp;type&nbsp;in&nbsp;(N'FN',&nbsp;N'IF',&nbsp;N'TF',&nbsp;N'FS',&nbsp;N'FT'))DROP&nbsp;FUNCTION&nbsp;[dbo].[fu_Constaint_ValidRmApertureId]GOCREATE&nbsp;FUNCTION&nbsp;[dbo].[fu_Constaint_ValidRmApertureId]( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@in_RM_ApertureID&nbsp;uniqueidentifier&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;,@in_DatumVon&nbsp;AS&nbsp;datetime&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;,@in_DatumBis&nbsp;AS&nbsp;datetime&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;,@in_Status&nbsp;AS&nbsp;integer&nbsp; )&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;RETURNS&nbsp;bit&nbsp; AS&nbsp;BEGIN&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;DECLARE&nbsp;@bNoCheckForThisCustomer&nbsp;AS&nbsp;bit&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;DECLARE&nbsp;@bIsInvalidValue&nbsp;AS&nbsp;bit&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;@bNoCheckForThisCustomer&nbsp;=&nbsp;'false'&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;@bIsInvalidValue&nbsp;=&nbsp;'false'&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;@in_Status&nbsp;=&nbsp;99&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;'false'&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;@in_DatumVon&nbsp;>&nbsp;@in_DatumBis&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;BEGIN&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;'true'&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;END&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;@bNoCheckForThisCustomer&nbsp;=&nbsp;'true' &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;@bIsInvalidValue&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;NOT&nbsp;EXISTS &nbsp;&nbsp;&nbsp;&nbsp;(&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T_Raum.RM_UID&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,T_Raum.RM_Status&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,T_Raum.RM_DatumVon&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,T_Raum.RM_DatumBis&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,T_Raum.RM_ApertureID&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM&nbsp;T_Raum&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHERE&nbsp;(1=1)&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AND&nbsp;T_Raum.RM_ApertureID&nbsp;=&nbsp;@in_RM_ApertureID&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AND&nbsp;@in_DatumVon&nbsp;>=&nbsp;T_Raum.RM_DatumVon&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AND&nbsp;@in_DatumBis&nbsp;<=&nbsp;T_Raum.RM_DatumBis&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AND&nbsp;T_Raum.RM_Status&nbsp;<>&nbsp;99&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;)&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;@bIsInvalidValue&nbsp;=&nbsp;'true'&nbsp;--&nbsp;IF&nbsp;!&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;@bIsInvalidValue&nbsp; END&nbsp;GOIF&nbsp;&nbsp;EXISTS&nbsp;(SELECT&nbsp;*&nbsp;FROM&nbsp;sys.check_constraints&nbsp;WHERE&nbsp;object_id&nbsp;=&nbsp;OBJECT_ID(N'[dbo].[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]')&nbsp;AND&nbsp;parent_object_id&nbsp;=&nbsp;OBJECT_ID(N'[dbo].[T_ZO_REM_AP_Raum_Reinigung]'))ALTER&nbsp;TABLE&nbsp;dbo.T_ZO_REM_AP_Raum_Reinigung&nbsp;DROP&nbsp;CONSTRAINT&nbsp;[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]GO--&nbsp;ALTER&nbsp;TABLE&nbsp;dbo.T_AP_Kontakte&nbsp;WITH&nbsp;CHECK&nbsp;ADD&nbsp;CONSTRAINT&nbsp;[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]&nbsp;&nbsp;ALTER&nbsp;TABLE&nbsp;dbo.T_ZO_REM_AP_Raum_Reinigung&nbsp;WITH&nbsp;NOCHECK&nbsp;ADD&nbsp;CONSTRAINT&nbsp;[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]&nbsp;CHECK&nbsp;(&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;NOT&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;(&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbo.fu_Constaint_ValidRmApertureId(ZO_RMREM_RM_UID,&nbsp;ZO_RMREM_GueltigVon,&nbsp;ZO_RMREM_GueltigBis,&nbsp;ZO_RMREM_Status)&nbsp;=&nbsp;1&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;)&nbsp;GOIF&nbsp;&nbsp;EXISTS&nbsp;(SELECT&nbsp;*&nbsp;FROM&nbsp;sys.check_constraints&nbsp;WHERE&nbsp;object_id&nbsp;=&nbsp;OBJECT_ID(N'[dbo].[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]')&nbsp;AND&nbsp;parent_object_id&nbsp;=&nbsp;OBJECT_ID(N'[dbo].[T_ZO_REM_AP_Raum_Reinigung]'))&nbsp;ALTER&nbsp;TABLE&nbsp;dbo.T_ZO_REM_AP_Raum_Reinigung&nbsp;CHECK&nbsp;CONSTRAINT&nbsp;[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]&nbsp;GO
打开App,查看更多内容
随时随地看视频慕课网APP
我要回答