【问题标题】:INSERT conflicted with foreign key - SQL Server bug?INSERT 与外键冲突 - SQL Server 错误?
【发布时间】:2009-12-15 19:41:06
【问题描述】:

更新:在 SQL Server 2008 上运行时不会发生此问题。所以这对于 SQL Server 2000 来说有些奇怪(或错误)。

我尝试在 SQL Server 2000 上进行简单的插入:

INSERT INTO UserAddresses (UserId, AddressId)
  SELECT UserId, Id
  FROM Addresses

我明白了:

INSERT 语句与 COLUMN FOREIGN KEY 约束 'FK569ABB5045EE0940'。冲突 发生在数据库“订单”表中 “地址”,“ID”列。

我很清楚这意味着什么,但我不明白为什么会发生冲突 - 请注意,我从 Addresses 表中插入了 ID,所以它们确实存在!为什么 SQL Server 在 Addresses 表的外键端找不到它们?我应该做傻事吗

SELECT * FROM Addresses 
WHERE Id NOT IN (SELECT Id FROM Addresses)

还是什么?

更多信息:ID 是 GUID,数据来自旧数据库(导入)。首先我填充地址,然后尝试插入用户地址。如果我做 SELECT TOP 100 ... 它可以工作...所以这是一些记录的问题,但我不明白为什么会发生。

CREATE TABLE [Addresses] (
    [Id] [uniqueidentifier] NOT NULL ,
     PRIMARY KEY  CLUSTERED ([Id])  ON [PRIMARY] ,
) ON [PRIMARY]
CREATE TABLE [Users] (
    [Id] [uniqueidentifier] NOT NULL ,
     PRIMARY KEY  CLUSTERED ([Id])  ON [PRIMARY] 
) ON [PRIMARY]
CREATE TABLE [UserAddresses] (
    [UserId] [uniqueidentifier] NOT NULL ,
    [AddressId] [uniqueidentifier] NOT NULL ,
    CONSTRAINT [FK569ABB5045EE0940] FOREIGN KEY 
    (
        [AddressId]
    ) REFERENCES [Addresses] (
        [Id]
    ),
    CONSTRAINT [UserAddressesToAddressFK] FOREIGN KEY 
    (
        [UserId]
    ) REFERENCES [Users] (
        [Id]
    )
) ON [PRIMARY]
ALTER TABLE Addresses ADD UserId UNIQUEIDENTIFIER
INSERT INTO Addresses (UserId, Id)
SELECT legacy_userid, legacy_single_useraddressid -- both are guids
FROM LegacyUsers INNER JOIN LegacyAddresses

更新:我刚刚完成,没有错误(查询批处理完成):

DECLARE c CURSOR FOR SELECT UserId, Id FROM Addresses
OPEN c
DECLARE @uid UNIQUEIDENTIFIER, @aid UNIQUEIDENTIFIER
FETCH NEXT FROM c INTO @uid, @aid
WHILE @@FETCH_STATUS = 0
BEGIN
   PRINT @aid
   INSERT INTO UserAddresses (UserId, AddressId)
   VALUES (@uid, @aid)
FETCH NEXT FROM c INTO @uid, @aid
END
CLOSE c
DEALLOCATE c

我想知道为什么在 foreach 游标工作时 INSERT 失败...

更新:哎呀,游标完成后,INSERT 也可以工作。但它永远不会独立工作。这是我的工作:

  1. 运行导入脚本以填充地址表
  2. 手动运行 INSERT - 失败
  3. 手动运行 CURSOR - 有效
  4. 从用户地址中删除
  5. 手动运行 INSERT - 现在可以使用了

这是魔法还是我完全是个白痴错过了什么?

更新:如果我这样做了

ALTER TABLE UserAddresses DROP CONSTRAINT FK569ABB5045EE0940

INSERT INTO UserAddresses (UserId, AddressId)
SELECT UserId, Id
FROM Addresses

    alter table UserAddresses 
        add constraint FK569ABB5045EE0940
        foreign key (AddressId) 
        references Addresses

它也有效。我认为这是 SQL Server 2000 中的一个错误,尽管有“从不责怪编译器”规则。

【问题讨论】:

  • UserAddresses 表的定义是什么?
  • 也许您想比CONSTRAINT [FK569ABB5045EE0940] 更直观地命名您的约束 - CONSTRAINT FK_UserAddresses_Addresses 左右怎么样?
  • 您确定我通过输入名称将约束命名为 FK569ABB5045EE0940 吗? ;-) 这是由 ORM 完成的,正如您在上面看到的那样,即使我将它们命名为 UserAddressesToAddressFK,只是它不能以相反的方式工作(我想 FluentNHibernate 限制,必须找出)。无论如何,我看不出这会有什么帮助。
  • 我唯一能想到的是你的一些 guid 不是 MSSQL 识别的格式,但它是一个很长的镜头,因为它不能解释为什么你的第二个 1 到 5 序列有效.. .
  • @Locksfree:列定义为带有 FK 的 GUID。所以不太可能

标签: sql sql-server sql-server-2000


【解决方案1】:

更新 - “哈利”架构

gbn 评论说这可能是一个架构问题。我更新了我的原始代码示例并且能够(几乎*)得到确切的错误。

(* 请注意,我在 2008 年运行此程序,而 OP 在 2000 年运行。SQL 2008 模式限定错误消息中的表。)

更新的代码 - “harry”架构

SET NOCOUNT ON
GO
--<< ========================== DROPS ==========================
IF OBJECT_ID('tempdb..#UserGUIDs') IS NOT NULL
    DROP TABLE #UserGUIDs
GO
IF OBJECT_ID('tempdb..#AddressGUIDs') IS NOT NULL
    DROP TABLE #AddressGUIDs
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('UserAddresses'))
    DROP TABLE [UserAddresses]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('Users'))
    DROP TABLE [Users]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('dbo.Addresses'))
    DROP TABLE dbo.[Addresses]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('harry.Addresses'))
    DROP TABLE harry.[Addresses]
GO

--<< ========================== TABLES ==========================
--<< Users
CREATE TABLE [Users] (
    [Id]        uniqueidentifier  NOT NULL DEFAULT NEWID()  PRIMARY KEY,
    [UserName]  varchar(10)       NOT NULL
) ON [PRIMARY]
GO

--<< Addresses
CREATE TABLE harry.[Addresses] (
    [Id]        uniqueidentifier  NOT NULL DEFAULT NEWID()  PRIMARY KEY,
    [Address1]  varchar(20)       NOT NULL
) ON [PRIMARY]
GO
CREATE TABLE dbo.[Addresses] (
    [Id]        uniqueidentifier  NOT NULL DEFAULT NEWID()  PRIMARY KEY,
    [Address1]  varchar(20)       NOT NULL
) ON [PRIMARY]
GO

--<< UserAddresses
CREATE TABLE [UserAddresses] (
    [UserId]    uniqueidentifier NOT NULL,
    [AddressId] uniqueidentifier NOT NULL,
    CONSTRAINT [FK569ABB5045EE0940]       FOREIGN KEY ([AddressId]) REFERENCES [Addresses] ([Id]),
    CONSTRAINT [UserAddressesToAddressFK] FOREIGN KEY ([UserId])    REFERENCES [Users] ([Id])
) ON [PRIMARY]
GO

--<< ========================== DATA ==========================
--<< Populate Users
CREATE TABLE #UserGUIDs ([UserId] uniqueidentifier)
GO
INSERT INTO [Users] ([UserName]) VALUES ('UserName1')
INSERT INTO [Users] ([UserName]) VALUES ('UserName2')
INSERT INTO [Users] ([UserName]) VALUES ('UserName3')
INSERT INTO [Users] ([UserName]) VALUES ('UserName4')
GO
INSERT INTO #UserGUIDs ([UserId]) SELECT [Id] FROM [Users]
GO

--<< Populate Addresses
CREATE TABLE #AddressGUIDs ([AddressId] uniqueidentifier)
GO
INSERT INTO harry.[Addresses] ([Address1]) VALUES ('1234 First Street')
INSERT INTO harry.[Addresses] ([Address1]) VALUES ('2345 Second Street')
INSERT INTO harry.[Addresses] ([Address1]) VALUES ('3456 Third Street')
INSERT INTO harry.[Addresses] ([Address1]) VALUES ('4567 Fourth Street')
GO
INSERT INTO #AddressGUIDs ([AddressId]) SELECT [Id] FROM harry.[Addresses]
GO

PRINT 'Users'
SELECT * FROM [Users]
PRINT 'Addresses'
SELECT * FROM harry.[Addresses]
GO

--<< ========================== TEST ==========================
--<< Populate UserAddresses
INSERT INTO UserAddresses (UserId, AddressId)
SELECT
    u.Id, -- UserID
    a.Id  -- AddressID
FROM harry.Addresses   AS a
CROSS JOIN Users AS u
GO

PRINT 'UserAddresses'
SELECT * FROM [UserAddresses]
GO

结果

Msg 547, Level 16, State 0, Line 4
The INSERT statement conflicted with the FOREIGN KEY constraint "FK569ABB5045EE0940". The conflict occurred in database "RGTest1", table "dbo.Addresses", column 'Id'.

原帖

queen3,这是我认为你正在尝试的一个完整的工作示例。我试图让它与 SQL 2000 兼容,但我只有 2005 和 2008 可用。

请创建一个新数据库并运行此脚本。如果它没有重复您尝试做的事情,请解释或发布修改后的代码。

此脚本按原样运行,但我确定与您的应用程序有所不同。

罗伯

代码

SET NOCOUNT ON
GO
--<< ========================== DROPS ==========================
IF OBJECT_ID('tempdb..#UserGUIDs') IS NOT NULL
    DROP TABLE #UserGUIDs
GO
IF OBJECT_ID('tempdb..#AddressGUIDs') IS NOT NULL
    DROP TABLE #AddressGUIDs
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('UserAddresses'))
    DROP TABLE [UserAddresses]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('Users'))
    DROP TABLE [Users]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('Addresses'))
    DROP TABLE [Addresses]
GO

--<< ========================== TABLES ==========================
--<< Users
CREATE TABLE [Users] (
    [Id]        uniqueidentifier  NOT NULL DEFAULT NEWID()  PRIMARY KEY,
    [UserName]  varchar(10)       NOT NULL
) ON [PRIMARY]
GO

--<< Addresses
CREATE TABLE [Addresses] (
    [Id]        uniqueidentifier  NOT NULL DEFAULT NEWID()  PRIMARY KEY,
    [Address1]  varchar(20)       NOT NULL
) ON [PRIMARY]
GO

--<< UserAddresses
CREATE TABLE [UserAddresses] (
    [UserId]    uniqueidentifier NOT NULL,
    [AddressId] uniqueidentifier NOT NULL,
    CONSTRAINT [FK569ABB5045EE0940]       FOREIGN KEY ([AddressId]) REFERENCES [Addresses] ([Id]),
    CONSTRAINT [UserAddressesToAddressFK] FOREIGN KEY ([UserId])    REFERENCES [Users] ([Id])
) ON [PRIMARY]
GO

--<< ========================== DATA ==========================
--<< Populate Users
CREATE TABLE #UserGUIDs ([UserId] uniqueidentifier)
GO
INSERT INTO [Users] ([UserName]) VALUES ('UserName1')
INSERT INTO [Users] ([UserName]) VALUES ('UserName2')
INSERT INTO [Users] ([UserName]) VALUES ('UserName3')
INSERT INTO [Users] ([UserName]) VALUES ('UserName4')
GO
INSERT INTO #UserGUIDs ([UserId]) SELECT [Id] FROM [Users]
GO

--<< Populate Addresses
CREATE TABLE #AddressGUIDs ([AddressId] uniqueidentifier)
GO
INSERT INTO [Addresses] ([Address1]) VALUES ('1234 First Street')
INSERT INTO [Addresses] ([Address1]) VALUES ('2345 Second Street')
INSERT INTO [Addresses] ([Address1]) VALUES ('3456 Third Street')
INSERT INTO [Addresses] ([Address1]) VALUES ('4567 Fourth Street')
GO
INSERT INTO #AddressGUIDs ([AddressId]) SELECT [Id] FROM [Addresses]
GO

PRINT 'Users'
SELECT * FROM [Users]
PRINT 'Addresses'
SELECT * FROM [Addresses]
GO

--<< ========================== TEST ==========================
--<< Populate UserAddresses
INSERT INTO UserAddresses (UserId, AddressId)
SELECT
    u.Id, -- UserID
    a.Id  -- AddressID
FROM Addresses   AS a
CROSS JOIN Users AS u
GO

PRINT 'UserAddresses'
SELECT * FROM [UserAddresses]
GO

【讨论】:

  • 如果你发现它在 SQL 2000 上失败(我怀疑它不会),在 SQL 2005 或 2008 上也试试看是否有区别。我使用 2008 创建并测试了脚本。
  • 我可以看到为什么对于两个具有不同用户的表会失败,但我的数据库中只有一个用户。如果我之后为我申请 FK,它不会失败。至于您的原始测试,对我来说并没有失败,而且我无法在 2005/8 测试,因为我没有安装它们。我将发布有关我所做工作的更多详细信息,但我仍然认为这是大批量插入的问题,因为它适用于 1×1 光标、TOP 1/100 以及之后应用 FK 时。所以这不是数据或模式的问题。不过,感谢您进行如此详细的调查。
  • 我添加了更多关于表格以及如何填充地址的详细信息。并不是说我认为它会有所帮助......目前我对 DROP/ADD CONSTRAINT 很好,所以这个问题只是出于好奇。只是一个奇怪的错误,我不知道也想理解。
【解决方案2】:

随意的想法...

您使用什么凭据、ORM 使用什么以及什么架构?

例如,表和 FK 实际上使用的是“bob”模式

  • bob.地址
  • bob.Users
  • bob.UserAddresses

但由于 SQL 2005 之前的用户/模式的东西,你是在“哈利”模式...

INSERT INTO UserAddresses (UserId, AddressId)
  SELECT UserId, Id
  FROM Addresses

-- is actually
INSERT INTO harry.UserAddresses (UserId, AddressId)
  SELECT UserId, Id
  FROM bob.Addresses
-- or
INSERT INTO bob.UserAddresses (UserId, AddressId)
  SELECT UserId, Id
  FROM harry.Addresses

我不止一次享受测试人员和开发人员因为缺乏合格的架构而获得不同结果的景象......

【讨论】:

  • 好点。我已经“去模式化”了我的测试代码。查看我帖子的更新。
【解决方案3】:

检查用户地址表。也许有人在表上定义了一个(坏的!)触发器,以某种方式对 Addresses 或 UserAddresses 表做了一些坏事。

【讨论】:

  • 整个数据库是在我导入之前由 ORM (NHibernate) 生成的。即使没有数据,它也是完全无辜的。
  • 触发器好不坏,只有当开发人员没有受过良好教育而无法正确使用它们时,它们才是坏的。
  • 触发器可以是好的,也可以是“坏的”。错误触发器的一个示例是以某种不透明的邪恶方式修改您的 UserAddresses 或 Addresses 表。我就是这个意思。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-24
  • 1970-01-01
相关资源
最近更新 更多