ALTER TABLE语句与FOREIGN KEY约束冲突


184

尝试在tblDomare表中添加外键时遇到问题;我在这里做错了什么?

CREATE TABLE tblDomare
(PersNR VARCHAR (15) NOT NULL,
fNamn VARCHAR (15) NOT NULL,
eNamn VARCHAR (20) NOT NULL,
Erfarenhet VARCHAR (5),
PRIMARY KEY (PersNR));

INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet)
Values (6811034679,'Bengt','Carlberg',10);

INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet)
Values (7606091347,'Josefin','Backman',4);

INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet)
Values (8508284163,'Johanna','Backman',1);

CREATE TABLE tblBana
(BanNR VARCHAR (15) NOT NULL,
PRIMARY KEY (BanNR));

INSERT INTO tblBana (BanNR)
Values (1);

INSERT INTO tblBana (BanNR)
Values (2);

INSERT INTO tblBana (BanNR)
Values (3);

ALTER TABLE tblDomare
ADD FOREIGN KEY (PersNR)
REFERENCES tblBana(BanNR);

错误信息:

ALTER TABLE语句与FOREIGN KEY约束“ FK_ tblDomare _PersN__5F7E2DAC” 冲突。数据库“ almu0004”的表“ dbo.tblBana”的列“ BanNR”中发生了冲突。

Answers:


333

发生这种情况的原因是,您尝试从to创建一个外键tblDomare.PersNRtblBana.BanNR但是/和中的值tblDomare.PersNR与中的任何值都不匹配tblBana.BanNR。您不能创建违反参照完整性的关系。


87
这是对我的答案,但是我仍然很难理解问题出在哪里,所以我以一个外行的例子为例。如果您有一个名为“ Orders”的表和一个名为“ Customers”的表,并且已删除了一些老客户,但没有删除他们的订单,那么,如果您决定从Orders.CustomerId到客户创建外键,则会出现此错误。 。ID。某些订单不再有相应的客户,因此无法添加外键。
乍得Hedgcock 2014年

10
这是一个检查值是否不正确的查询:从ReferrerTable左连接中选择与众不同的ReferrerTable.referenceColumn,然后在ReferedTable.referenceColumn = ReferrerTable.referenceColumn上将ReferedTable加入其中,referredTable.referenceColumn为null;
jumxozizi

6
在紧要关头,您还可以使用“ ALTER TABLE tablename WITH NOCHECK ...”选项添加FK。即使现有数据违反了约束,这也允许您添加关系。首先清理数据显然更好,但这至少为您提供了另一种选择。
DaveInMaine '16

2
@DaveInMaine如果有人“在需要时”停用数据库约束,那么我会问为什么首先要对它们进行麻烦,如果一个人对数据库完整性不感兴趣,为什么不跳过它们。
Smutje '16

1
多么糟糕的错误消息。曾经看过它,但是现在我以为某些东西已损坏使我完全措手不及
Simon_Weaver

42

这个查询对我来说非常有用。它显示所有不匹配的值

select FK_column from FK_table
WHERE FK_column NOT IN
(SELECT PK_column from PK_table)

37

试试这个解决方案:

表中有一个数据项,其关联值在您要用作主键表的表中不存在。使表为空或将关联的值添加到第二个表。


29

可以使用带有NOCHECK ...的ALTER TABLE表名来创建外键,这将允许违反外键的数据。

添加FK的“ ALTER TABLE tablename WITH NOCHECK ...”选项-此解决方案对我有用。


17
请注意,允许此类违反行为会破坏外键约束的目的。
改革后

危险的... !!! 仅当您不想丢失表中当前数据时才应使用。但是即使如此,为什么不做备份然后再删除无效的ID。
Andrei Bazanov

我需要通过java / spring / code来实现,而不是直接通过SQL查询来实现,这是如何通过以下代码来实现的:@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.DETACH) @JoinTable(name = "tbUsuariosTipoOcorrencia", joinColumns = { @JoinColumn(name = "idUsuario") }, inverseJoinColumns = { @JoinColumn(name = "idTipoOcorrencia") }) 我是通过数据库查询来解决的:alter table tbUsuariosTipoOcorrencia WITH NOCHECK add constraint FKnbxg3ua7b8c5d53wps69q6jh foreign key (idUsuario) references tbUsuarios
Francisco Souza

11

我想,外键表中的列值应与主键表中的列值匹配。如果我们试图在两个表之间创建外键约束,其中一列内的值(将成为外键)与主键表的列值不同,则它将抛出该消息。

因此,始终建议仅在外键列中插入主键表列中存在的那些值。

对于前。如果主表列的值是1、2、3,并且在外键列中插入的值是不同的,则该查询将不会执行,因为它期望该值在1和3之间。


11

在向表中添加外键之前,请执行以下操作

  1. 确保表必须为空或列数据应匹配。
  2. 确保它不为空。
  3. 如果表中包含不要进行设计和更改,请手动进行。

    alter table表1添加外键(列名)的引用表2(列名)

    alter table表1 alter column Column Name属性不为null


10

从表中清除数据,然后在它们之间建立关系。


谢谢,最大 如果他们有数据,即使关系完美,对我也有用。Update-Database命令将不起作用。
robert jebakumar2 '16

只要根据创建的外键它们是有效的,就不必删除任何数据。
jumxozizi

7

尝试DELETE从中获取当前数据tblDomare.PersNR。因为中的值tblDomare.PersNR与中的任何值都不匹配tblBana.BanNR


@agenc我回答了你的问题吗?
思想家贝尔

3

我也有此错误,因为Smutje要求确保您的基本外键表的外键列中没有引用表中没有的值,即(基本外键表中的每个值(外键)也必须在您的参考表列中)先清空您的基本外键表,然后再设置外键


2

您输入的数据表(tbldomare)与您分配的主键表数据不匹配。在tbldomare之间编写代码,并添加此词(不选中),然后执行代码。

例如,您输入了一个表,将这些数据

INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet)
Values (6811034679,'Bengt','Carlberg',10);

并且您分配了一个foreign key表以仅接受1,2,3

您有两种解决方案:一种是删除输入的数据,然后执行代码。另一个是写这个词(不带nocheck),把它放在你的表名之间,并像这样添加

ALTER TABLE  tblDomare with nocheck
ADD FOREIGN KEY (PersNR)
REFERENCES tblBana(BanNR);

2

这发生在我身上,因为我正在设计数据库,所以我注意到我在主表上更改了种子,现在关系表在主表上没有外键。

因此,我需要截断两个表,它现在可以工作了!


2

您应该查看表中的行上是否有任何数据。如果为“是”,则应截断表,否则可以使它们在tblDomare.PersNRto tblBana.BanNR和vise-verse 处具有相同数量的数据。


2

Smutje是正确的,Chad HedgeCock提供了一个很好的外行榜样。我想通过提供一种查找/删除这些记录的方法来建立乍得的榜样。我们将“客户”作为父级,“订单”作为子级。CustomerId是公共字段。

select * from Order Child 
left join Customer Parent on Child.CustomerId = Parent.CustomerId
where Parent.CustomerId is null 

如果您正在阅读此主题...您将获得结果。这些是孤儿。从“订购子项”中选择*,然后在Child.CustomerId = Parent.CustomerId上加入Customer Parent,其中Parent.CustomerId为null请注意右下角的行数。

去验证与需要删除的人,您将要删除这些行!

begin tran 
delete Order
from Order Child 
left join Customer Parent on Child.CustomerId = Parent.CustomerId
where Parent.CustomerId is null 

运行第一位。检查行数=您所期望的

提交tran

commit tran 

小心。有人草率的编程使您陷入困境。在删除这些孤儿之前,请确保了解原因。也许父母需要恢复。


谢谢回复。我正在使用stackoverflow数据库(实际上是gamedev),并且在与用户LEFT JOIN徽章时发现了两个NULL。难怪约束没有奏效……
尼古拉斯·汉弗莱

1

在我的场景中,使用EF,尝试在现有数据上创建此新外键时,我错误地尝试在创建外键之后填充数据(建立链接)。

解决方法是在创建外键之前填充数据,因为它会检查所有数据以查看链接是否确实有效。因此,如果您尚未填充它,则可能无法工作。


1

我在项目中遇到了一些问题。

在此处输入图片说明

在子表中,没有任何记录ID等于1和11

法师

我插入了ID等于1和11的DEAL_ITEM_THIRD_PARTY_PO表,然后可以创建FK



0

当您在表B中定义外键时,它引用表A的主键,这意味着当值在B中时,它必须在表A中。这是为了防止对表进行不一致的修改。

在您的示例中,表包含:

tblDomare与PRIMARY KEY (PersNR)

PersNR     |fNamn     |eNamn      |Erfarenhet
-----------|----------|-----------|----------
6811034679 |'Bengt'   |'Carlberg' |10
7606091347 |'Josefin' |'Backman'  |4
8508284163 |'Johanna' |'Backman'  |1
---------------------------------------------

tblBana:

BanNR
-----
1
2
3
-----

这个说法:

ALTER TABLE tblDomare
ADD FOREIGN KEY (PersNR)
REFERENCES tblBana(BanNR);

表示任何tblDomare与key PersNR对应的行必须tblBana在key的表中具有对应关系BanNR。您的错误是因为您插入的行中tblDomare没有对应关系tblBana

2个解决方案来解决您的问题: -无论是在加线tblBanaBanNR in (6811034679, 7606091347, 8508284163) - or remove all lines intblDomare that have no correspondance intblBana`(但你的表是空的)

一般建议:填充表之前,应具有外键约束。这里使用外键是为了防止表的用户使用不一致的表填充表。


-3

而且仅供参考,以防万一,您需要进行所有数据引用检查并且没有发现任何坏数据……显然,不可能在两个表和字段之间创建外键约束,而这些字段是两个表中的主键!不要问我我怎么知道的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.