Впровадження SQL Server 2005 MySQL ЗАМІНИТЬ НА?


86

MySQL має цю неймовірно корисну, але запатентовану REPLACE INTOкоманду SQL.

Чи можна це легко емулювати в SQL Server 2005?

Починаючи нову транзакцію, роблячи Select()і потім або UPDATEабо INSERTі COMMITзавжди трохи болю, особливо при виконанні його в додатку , і тому завжди тримати 2 версії заяви.

Цікаво, чи існує простий та універсальний спосіб реалізації такої функції в SQL Server 2005?

Відповіді:


60

Це те, що мене дратує у MSSQL ( розмова в моєму блозі ). Я бажаю, щоб MSSQL підтримувався upsert.

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

Існує дещо кращий спосіб у цій публікації , в основному:

--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, ... )

Зараз це насправді лише одна операція вводу-виводу, але жахливий код :-(


Щиро дякую! Зберігає Select і часто навіть не потребує взаємодії у ситуаціях, коли я можу бути впевнений, що між Оновленням та "моєю" вставкою для цього ключа немає іншої вставки.
Майкл Штум

2
@Michael Вам краще мати унікальний індекс у цій таблиці та обробляти помилки, що повторюються, якщо ви збираєтеся використовувати це рішення.
Сем Шафран

3
@Keith Ваш оператор злиття не працює. MERGEне підтримує WHEREпункт, вам доведеться переписати це, використовуючи USINGта ON. Крім того, якщо ви не додасте WITH (HOLDLOCK), INSERTможе статися гонка, і можуть статися паралельні s, причому одна з них зазнає невдачі через зіткнення ключів.
Євген Березовський

Так, як зазначено тут: weblogs.sqlteam.com/dang/archive/2009/01/31/… MERGE не є атомним. Він вимикає неявний блокування оновлення, але звільняє його перед виконанням вставки, що спричиняє перегоновий стан, що може призвести до порушень первинного ключа. Ви повинні використовувати явний HOLDLOCK на додаток до неявного UPDLOCK, щоб операція була атомною. По суті, він не є атомним, незважаючи на те, що здається єдиним твердженням.
Трійко

1
Синтаксис MERGE помилковий, і це виправлено в останній відповіді того ж автора: stackoverflow.com/a/243670/24472
Ларрі,

21

Функціональність, яку ви шукаєте, традиційно називається UPSERT. Найменш знаючи, як це називається, може допомогти вам знайти те, що ви шукаєте.

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

Злиття було доступне в бета-версії 2005 року, але вони видалили його в остаточному випуску.


18

Те, що робить upsert / merge - це щось на зразок ...

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

Тож, сподіваємось, поєднання цих статей і цього псевдокоду може зрушити ситуацію з місця.


10

Я написав допис у блозі з цього приводу.

Суть полягає в тому, що якщо ви хочете дешеві оновлення і хочете бути безпечними для одночасного використання, спробуйте:

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 операції для вставок. Отже, якщо ви, як правило, оновлюєтеся, це безпечний дешевий варіант.

Я також був би дуже обережним, щоб не використовувати нічого, що небезпечно для одночасного використання. Дійсно легко отримати порушення первинного ключа або дублікати рядків у виробництві.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.