T-SQL IF условие не работает должным образом - PullRequest
1 голос
/ 02 октября 2010

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

Независимо от того, что определено ограничение уникального ключа, я использую условие IF () (до оператора INSERT), чтобы проверить наличие дублирующейся записи, которая может уже существовать.

Однако условный оператор, который я использую для проверки на наличие дублирующейся записи, по-видимому, не влияет на выполнение INSERT или нет. - т. е. когда в sproc передается дубликат записи, возникает исключение «Нарушение ограничения UNIQUE KEY ...».

Вот образец моего ростка:

BEGIN       
    if
        (SELECT Count(f1)
        FROM table
        WHERE f1 = @f1
        AND f2= @f2) 
    <= 0
    BEGIN
        INSERT INTO table
        (f1,f2)
        VALUES
        (@f1, @f2)

        RETURN @@IDENTITY
    END
END

Что-то не так с моим синтаксисом? Или, может быть, я поступаю неправильно?

Ответы [ 5 ]

3 голосов
/ 02 октября 2010

Если вы используете SQL Server 2008 или новее, вы должны использовать оператор MERGE:

MERGE INTO table AS t
USING (VALUES (@f1, @f2)) AS s (f1, f2)
    ON s.f1 = t.f1
        AND s.f2 = t.f2
WHEN NOT MATCHED BY t THEN
    INSERT (f1, f2) VALUES (@f1, @f2)
3 голосов
/ 02 октября 2010

Count(field) считает значения, которые не равны нулю.
Это может отличаться от count(*), который считает строки.

Но я бы не рекомендовал использовать count здесь.
Посмотрите на этот вопрос .

2 голосов
/ 02 октября 2010

Это более безопасно для параллелизма:

INSERT INTO table
SELECT @f1, @f2, @f3
  FROM TABLE WITH (UPDLOCK, HOLDLOCK)
 WHERE NOT EXISTS(SELECT NULL
                    FROM table
                   WHERE f1 = @f1
                     AND f2 = @f2
                     AND f3 = @f3) 

Или, если вы хотите сохранить логику принятия решения (но менее безопасную параллелизм), используйте NOT EXISTS:

IF NOT EXISTS(SELECT NULL
                FROM table
               WHERE f1 = @f1
                 AND f2 = @f2
                 AND f3 = @f3) 
BEGIN

    INSERT INTO table
      (f1,f2, f3)
    VALUES
      (@f1, @f2, @f3)

    RETURN @@SCOPE_IDENTITY

END
1 голос
/ 02 октября 2010

Спасибо за ваш ввод OMG / Martin, но оказывается, что корень моей проблемы был из-за значения параметра, равного нулю.

В частности:

--sproc params
@f1 int,
@f2 nvarchar(30),
@f3 datetime = null --<<a null value will screw up the IF() condition

IF(SELECT COUNT(f1)
FROM table
WHERE f1 = @f1
AND f2 = @f2
AND f3 = @f3)
<1

BEGIN
  INSERT INTO....
END

Обратите внимание, что значение по умолчанию для параметра @ f3 равно нулю. Таким образом, в случае, когда вызывающая сторона sproc не передает параметр @ f3, условие IF () вернет 0 (ноль), даже если есть совпадающие @ f1, @ f2 и null @ f3.

Например: скажем, в таблице уже есть запись

f1   f2   f3
--------------
45   foo  NULL

Теперь вызывающая сторона запускает спрока, отправляя его:

@ f1 = 45

@ f2 = Foo

(обратите внимание, что вызывающая сторона не указывает @ f3)

Если условие IF (), если оно выполнено, оно вернет 0 (ноль). Странно, а? Интуитивно я думаю, что условие вернет 1, поскольку параметры точно соответствуют существующим значениям в таблице.

Чтобы немного усложнить ситуацию (во всяком случае, для меня), это то, что хотя IF () завершается успешно (возвращает ноль), я получаю исключение "Нарушение ограничения UNIQUE KEY ..". На самом деле, я не удивлен, что возникает исключение, так как я считаю, что значения параметров идеально соответствуют существующей записи в таблице - для меня запутанная часть, почему условие IF () противоречит исключению нарушения .

Кстати, OMGPonies, я пытался использовать ваше предложение (EXISTS), и появляются те же симптомы. По-видимому, NULL-фактор усложняет ситуацию.

0 голосов
/ 02 октября 2010
SET NOCOUNT ON  
SELECT * FROM table  
WHERE f1 = @f1
        AND f2= @f2  

IF @@ROWCOUNT = 0  
BEGIN  
 INSERT INTO table  
        (f1,f2)  
        VALUES  
        (@f1, @f2)  


    RETURN @@IDENTITY  
END  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...