INSERT конфликтует с внешним ключом - ошибка SQL Server? - PullRequest
2 голосов
/ 12 октября 2009

ОБНОВЛЕНИЕ: проблема не возникает при запуске с SQL Server 2008. Так что это странно (или неправильно) с SQL Server 2000.

Я пытаюсь сделать простую вставку в SQL Server 2000:

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

и я получаю это:

Оператор INSERT конфликтует с КОЛОНКА ИНОСТРАННЫЙ КЛЮЧ ограничение 'FK569ABB5045EE0940. Конфликт произошло в базе данных «Заказы», ​​таблица «Адреса», столбец «Идентификатор».

Я хорошо знаю, что это значит, но не могу понять, почему происходит конфликт - обратите внимание, что я вставляю идентификаторы из таблицы адресов, чтобы они действительно существовали! Почему SQL Server не может найти их в конце внешнего ключа в таблице адресов? Должен ли я сделать глупо

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

или что?

Еще немного информации: идентификаторы - это GUID, данные поступают из устаревшей БД (импорт). Сначала я заполняю Адреса, затем пытаюсь вставить в UserAddresses. Если я выберу 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

Интересно, почему INSERT терпит неудачу, в то время как курсор foreach работает ...

ОБНОВЛЕНИЕ: упс, после завершения курсора, INSERT тоже работает. Но это никогда не работает автономно. Вот что я делаю:

  1. Запустите скрипт импорта, чтобы он заполнил таблицу адресов
  2. Вручную запустить INSERT - не получается
  3. Запустите CURSOR вручную - все работает
  4. DELETE FROM UserAddresses
  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, несмотря на правило «никогда не вините компилятор».

Ответы [ 3 ]

1 голос
/ 12 октября 2009

Обновление - Схема "Гарри"

gbn отметил, что это может быть проблемой схемы. Я обновил свой оригинальный пример кода и смог получить (почти *) точную ошибку.

(* Обратите внимание, что я запускаю это в 2008 году, а OP - в 2000. Схема SQL 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('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.

Пожалуйста, создайте новую базу данных и запустите этот скрипт. Если это не дублирует то, что вы пытаетесь сделать, объясните или просто опубликуйте измененный код.

Этот скрипт работает как есть, но я уверен, что есть что-то, что отличается от вашего приложения.

Rob

код

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
0 голосов
/ 12 октября 2009

Случайная мысль ...

Какие учетные данные вы используете, что использовали ORM и какую схему?

например, таблицы и FK фактически используют схему "bob"

  • bob.Addresses
  • 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

Не раз мне нравилось, как тестеры и разработчики получали разные результаты из-за отсутствия подходящей схемы ...

0 голосов
/ 12 октября 2009

Проверьте таблицу UserAddresses. Может быть, кто-то определил (BAD!) Триггер в таблице, который каким-то образом делает зло в таблице адресов или пользовательских адресов.

...