Нарушение ограничения UNIQUE KEY во время обновления SQL

У меня есть простая таблица базы данных (SQL Server 2008 R2 Express), которая имеет следующее определение:

ID         INT          Auto Inc, PK
Name       VARCHAR(64)  Unique Key
Telephone  VARCHAR(128)

У меня есть хранимая процедура, которую я выполняю для обновления записей в таблице, которая в основном делает следующее:

UPDATE customers
SET    Name = @name, Telephone = @Telephone
WHERE  id = @id

В настоящее время у меня есть две записи в таблице

ID   Name    Telephone
1    Fred    01234 567890
2    John    09876 543210

Когда я вызываю свою хранимую процедуру для обновления телефонного номера Джона, SQL, который эффективно выполняется, выглядит следующим образом:

UPDATE customers
SET    Name = 'John', Telephone = '02468 135790'
WHERE  id = 2

Это создает нарушение UNIQUE KEY в поле Name. Теперь, когда поле Имя на самом деле не меняется, почему это происходит?

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

Учитывая, что в моей таблице на самом деле гораздо больше полей, должен быть общий обходной путь, который я могу использовать для предотвращения этих проблем с ложными ограничениями, без необходимости создавать множество хранимых процедур для обновления определенных полей?

Изменить: приведенная выше таблица была упрощена, чтобы сделать вопрос более управляемым, я почти уверен, что не пропустил ничего важного, но для информации фактическое определение таблицы выглядит следующим образом.

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[companies](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [typeId] [int] NOT NULL,
    [name] [varchar](64) NOT NULL,
    [displayName] [varchar](128) NOT NULL,
    [deliveryAddress] [varchar](1024) NOT NULL,
    [invoiceAddress] [varchar](1024) NOT NULL,
    [telephone] [varchar](64) NOT NULL,
    [fax] [varchar](64) NOT NULL,
    [email] [varchar](256) NOT NULL,
    [website] [varchar](256) NULL,
    [isActive] [bit] NOT NULL,
 CONSTRAINT [PK_companies] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
 CONSTRAINT [Unique Display Name] UNIQUE NONCLUSTERED 
(
    [displayName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
 CONSTRAINT [Unique Name] UNIQUE NONCLUSTERED 
(
    [name] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[companies]  WITH CHECK ADD  CONSTRAINT [Company Type] FOREIGN KEY([id])
REFERENCES [dbo].[companyTypes] ([id])
GO

ALTER TABLE [dbo].[companies] CHECK CONSTRAINT [Company Type]
GO

...и хранимая процедура

ALTER PROCEDURE UpdateCompany

    @id                 INT,
    @typeId             INT,
    @name               VARCHAR(64),
    @displayName        VARCHAR(128),
    @deliveryAddress    VARCHAR(1024),
    @invoiceAddress     VARCHAR(1024),
    @telephone          VARCHAR(64),
    @fax                VARCHAR(64),
    @email              VARCHAR(256),
    @website            VARCHAR(256),
    @isActive           BIT

AS
BEGIN

    UPDATE  companies
    SET     typeid = @typeid,
            name = @name,
            displayname = @displayname,
            deliveryAddress = @deliveryAddress,
            invoiceAddress = @invoiceAddress,
            telephone = @telephone,
            fax = @fax,
            email = @email,
            website = @website,
            isActive = @isActive

    EXEC    GetCompany @id


END
GO

person Bryan    schedule 30.08.2011    source источник
comment
Это определенно звучит неправильно. Вы уверены, что на самом деле нет дубликатов и что уникальное ограничение ранее было включено без опции WITH CHECK, которая проверяла бы существующие данные? Или у вас есть какие-то триггеры, которые могут вызывать это?   -  person Martin Smith    schedule 31.08.2011
comment
@Martin: на 100% уверен, что дубликата нет, однако, если честно, я не знаком с опцией WITH CHECK.   -  person Bryan    schedule 31.08.2011
comment
У вас есть триггер или что-то еще, влияющее на обновление?   -  person JNappi    schedule 31.08.2011
comment
@Bryan - На самом деле не уверен на 100%, относится ли это к уникальным ограничениям или просто проверяет ограничения и FK, но если у вас нет дубликатов, этого не может быть. Что насчет триггеров?   -  person Martin Smith    schedule 31.08.2011
comment
Я нигде не вижу никаких триггеров. Я унаследовал эту пустую структуру базы данных, которая, насколько мне известно, представляет собой просто набор таблиц и отношений.   -  person Bryan    schedule 31.08.2011
comment
@Bryan - Можете ли вы опубликовать свой фактический код хранимой процедуры?   -  person Martin Smith    schedule 31.08.2011
comment
Я обновил вопрос, чтобы дать полное SQL-определение таблицы, на тот случай, если я пропустил что-то важное в своей первоначальной упрощенной версии вопроса.   -  person Bryan    schedule 31.08.2011
comment
@Bryan: вам не хватает WHERE в вашем выражении UPDATE, поэтому в настоящее время он попытается обновить все строки.   -  person Martin Smith    schedule 31.08.2011
comment
О, Боже! Не могу поверить, что я пропустил это! Думаю, пора закругляться. Пожалуйста, напишите в качестве ответа, Мартин, и я приму (и смущаюсь, оставив этот вопрос открытым для всеобщего обозрения).   -  person Bryan    schedule 31.08.2011
comment
Вероятно, хорошо, что у вас есть уникальное ограничение на имя ... иначе вся таблица была бы залита шлангом.   -  person NotMe    schedule 31.08.2011
comment
@Bryan - Когда-нибудь это случается со всеми нами!   -  person Martin Smith    schedule 31.08.2011


Ответы (1)


Вам не хватает WHERE в вашем операторе UPDATE, поэтому в настоящее время он попытается обновить все строки в таблице с одинаковыми значениями.

person Martin Smith    schedule 30.08.2011
comment
Это случается даже с лучшими из нас. Откуда мне это знать, спросите вы? :) - person Adriano Carneiro; 31.08.2011