Исходный код вики INSERT or UPDATE
Редактировал(а) Alexandr Fokin 2023/12/16 14:11
Последние авторы
| author | version | line-number | content |
|---|---|---|---|
| 1 | Solutions for INSERT OR UPDATE on SQL Server | ||
| 2 | https://stackoverflow.com/questions/108403/solutions-for-insert-or-update-on-sql-server | ||
| 3 | |||
| 4 | |||
| 5 | 1) | ||
| 6 | |||
| 7 | {{code language="sql"}} | ||
| 8 | DECLARE @key INT = 12 | ||
| 9 | DECLARE @msg NVARCHAR(MAX) = 'L2' | ||
| 10 | |||
| 11 | BEGIN TRAN | ||
| 12 | IF EXISTS ( | ||
| 13 | SELECT * | ||
| 14 | FROM DBO.LOG2ENTITY WITH (UPDLOCK, SERIALIZABLE) | ||
| 15 | WHERE ID = @key | ||
| 16 | ) | ||
| 17 | BEGIN | ||
| 18 | UPDATE DBO.LOG2ENTITY | ||
| 19 | SET | ||
| 20 | Message = @msg | ||
| 21 | WHERE ID =@key | ||
| 22 | END | ||
| 23 | ELSE | ||
| 24 | BEGIN | ||
| 25 | INSERT INTO DBO.LOG2ENTITY (Message) | ||
| 26 | VALUES (@msg) | ||
| 27 | END | ||
| 28 | COMMIT TRAN | ||
| 29 | |||
| 30 | {{/code}} | ||
| 31 | |||
| 32 | |||
| 33 | 2) Идея-костыль: | ||
| 34 | 2.1) Если строка отсутствует в таблице (EXSIST SELECT) | ||
| 35 | (Опционально возможен сразу UPDLOCK), | ||
| 36 | то пробуем выполнить вставку строки, в случае возникновения ошибки, что ключ уже существует, игнорируем ее. | ||
| 37 | (При этом возможно, что вместо большей части данных пока что подставляем значения по умолчанию, важен только ключ) | ||
| 38 | 2.2) Явно начинаем транзакцию | ||
| 39 | 2.2.1) Извлекаем строку с блокировкой (WITH UPDLOCK). К данному этапу строка уже гарантированно есть в БД (Если не рассматривать удаление). | ||
| 40 | 2.2.2) При необходимости проверяем состояние строки. Обеспечивая идемпотентность и корректность с точки зрения многопоточности и версионности. | ||
| 41 | 2.2.3) При необходимости обновляем строку. |