2008-08-01 5 views
69

У MySQL есть эта невероятно полезная, но правильная команда SQL REPLACE INTO.Выполнение SQL Server 2005 MySQL ЗАМЕНИТЬ В?

Можно ли легко эмулировать его в SQL Server 2005?

Начиная новую транзакцию, делая Select(), а затем либо UPDATE или INSERT и COMMIT всегда немного боли, особенно при выполнении его в приложении, и поэтому всегда держать 2 версии заявления.

Интересно, существует ли простой способ и реализовать универсальный способ реализации такой функции в SQL Server 2005?

ответ

53

Это меня раздражает MSSQL (rant on my blog). Я хочу, чтобы MSSQL поддерживал upsert.

@ код Dillie-O является хорошим способом в старых SQL версий (+1 голосов), но она по-прежнему в основном две операции ввода-вывода (exists, а затем update или insert)

Там в немного лучший способ на this post, в основном:

--try an update 
update tablename 
set field1 = 'new value', 
    field2 = 'different value', 
    ... 
where idfield = 7 

--insert if failed 
if @@rowcount = 0 and @@error = 0 
    insert into tablename 
      (idfield, field1, field2, ...) 
    values (7, 'value one', 'another value', ...) 

Это уменьшает его на одной операции ввода-вывода, если это обновление, или два, если вставка.

MS SQL2008 вводит merge из SQL: 2003 стандарт:

merge tablename as target 
using (values ('new value', 'different value')) 
    as source (field1, field2) 
    on target.idfield = 7 
when matched then 
    update 
    set field1 = source.field1, 
     field2 = source.field2, 
     ... 
when not matched then 
    insert (idfield, field1, field2, ...) 
    values (7, source.field1, source.field2, ...) 

Теперь это действительно только одна операция ввода-вывода, но ужасный код :-(

+0

Отлично, спасибо! Сохраняет выбор и часто даже не нуждается в трансакции в ситуациях, когда я могу быть уверен, что между обновлением и «моей» вставкой нет другой вставки для этого ключа. – 2008-09-20 15:41:27

19

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

Я не думаю, что у SQL Server 2005 есть отличные способы сделать это. 2008 представляет заявление MERGE, которое может быть использовано для его выполнения, как показано в: http://www.databasejournal.com/features/mssql/article.php/3739131 или http://blogs.conchango.com/davidportas/archive/2007/11/14/SQL-Server-2008-MERGE.aspx

Слияние было доступно в бета-версии 2005 года, но они были удалены в финальной версии.

15

Что upsert/слияние делает что-то эффект ...

IF EXISTS (SELECT * FROM [Table] WHERE Id = X) 
    UPDATE [Table] SET... 
ELSE 
    INSERT INTO [Table] 

Так, мы надеемся, сочетание этих статей и этот псевдо код может получить вещи, перемещающиеся.

9

Я написал blog post about this issue

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

update t 
set hitCount = hitCount + 1 
where pk = @id 

if @@rowcount < 1 
begin 
    begin tran 
     update t with (serializable) 
     set hitCount = hitCount + 1 
     where pk = @id 
     if @@rowcount = 0 
     begin 
     insert t (pk, hitCount) 
     values (@id,1) 
     end 
    commit tran 
end 

Таким образом, у вас есть 1 операция для обновлений и максимум 3 операции для вставок. поэтому, если вы вообще обновляете, это безопасный дешевый вариант.

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