2013-09-22 4 views
3

Я пытаюсь реализовать контрольное ограничение в таблице, чтобы записи не могли быть вставлены там, где существует запись, для которой два столбца («Int_1» и «Int_2» «) уже есть значение, которое мы пытаемся вставить, например:Проверить ограничение UDF с несколькими входными параметрами, не работающими

ID  Name  Int_1  Int_2 
1  Dave  1   2 

подставляя (2, Стив, 2, 2) в таблице выше, было бы хорошо, равно как и (3, Майк, 1, 3) , но вставка значений, где Int_1 AND Int_2 уже существует, не допускается, т. е. (4, Стюарт, 1, 2) является незаконным.

Я думал, определяя, таким образом, мой стол будет работать:

CREATE TABLE [Table](
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [Name] [varchar](255) NOT NULL, 
    [Int_1] [int] NOT NULL, 
    [Int_2] [int] NOT NULL, 
    CONSTRAINT [chk_Stuff] CHECK (dbo.chk_Ints(Int_1, Int_2)=1)) 

где: определяется dbo.chk_Ints:

CREATE FUNCTION [dbo].[chk_Ints](@Int_1 int,@Int_2 int) 
RETURNS int 
AS 
BEGIN 

DECLARE @Result int 

IF NOT EXISTS (SELECT * FROM [Table] WHERE Int_1 = @Int_1 AND Int_2 = @Int_2) 
BEGIN 
    SET @Result = 1 
END 
ELSE 
BEGIN 
    SET @Result = 0 
END 

RETURN @Result 
END 

GO 

При использовании комбо выше, если я пытаюсь вставить любой записи вообще, SQL говорит мне, что я нарушил ограничение на проверку. Я могу удалить все строки из таблицы и попытаться вставить первую запись, а SQL говорит мне, что я нарушил ограничение, которое я не мог сделать!

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

Заранее спасибо :)

+5

Весь взлом с UDF и контрольным ограничением является полным излишеством. Просто создайте * уникальный индекс * на '(int_1, int_2)' –

+0

Спасибо. Это намного проще, чем я пытался это сделать! – LeeCambl

ответ

10

Да, это может показаться непонятным, пока вы не поймете, что происходит, в этот момент он становится совершенно очевидным.

Функция вызывается для значений, которые находятся в строке, которую вы пытаетесь вставить. Но подумайте, как называется функция. Это вызов проверки, который вызывает его.

Далее подумайте о передаваемых параметрах. Откуда они? Согласно определению контрольное ограничение берет их из столбцов Int_1 и Int_2.

Таким образом, он передает их как значения столбца. Но значения столбцов должны принадлежать строке. Какая строка в этом случае? Тот, который вы пытаетесь вставить!

Это означает, что ваша строка is, вставленная в этот момент, только транзакция все еще находится на рассмотрении. И все же тот факт, что строка находится в таблице, имеет решающее значение, потому что это то, что функция находит и сообщает с результатом 1.

Таким образом, то, что происходит это:

  • вы пытаетесь вставить строку,

  • функция видит эту строку и говорит, что строка с заданными параметрами уже существует,

  • проверочное ограничение "реагирует" соответствующим образом путем запрета вставки,

  • Вставка откидывается назад.

Конечно, теперь, когда вы осознаете все это, легко придумать другую логику проверки дубликатов. В принципе, ваша функция должна «помнить», что новая строка уже находится в таблице, и поэтому она должна попытаться определить, нарушает ли ее присутствие в таблице любые правила, которые вы хотите установить. Можно, например, считать строки, соответствующие заданным параметрам и посмотреть, если результат не больше, чем 1:

IF (SELECT COUNT(*) FROM [Table] WHERE Int_1 = @Int_1 AND Int_2 = @Int_2) < 2 
BEGIN 
    SET @Result = 1 
END 
ELSE 
BEGIN 
    SET @Result = 0 
END 

Однако вся идея использования функции в проверочном ограничении для этого задания очень намного уступает, просто добавляя уникальное ограничение на два столбца, как suggested by @a_horse_with_no_name. Сделайте это:

ALTER TABLE [Table] 
ADD CONSTRAINT UQ_Table_Int1_Int2 UNIQUE (Int_1, Int_2); 

и вы можете забыть о дубликатах.

+0

Отличное объяснение, спасибо большое. Это очевидно, когда вы так выразились. Я добавил уникальное ограничение ключа, и все работает как ожидалось. Спасибо вам обоим. – LeeCambl

Смежные вопросы