Исходный код вики INSERT or UPDATE
Редактировал(а) Alexandr Fokin 2023/12/16 14:11
Скрыть последних авторов
| author | version | line-number | content |
|---|---|---|---|
| |
6.1 | 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 | |||
| |
7.1 | 5 | 1) |
| 6 | |||
| |
2.1 | 7 | {{code language="sql"}} |
| |
3.1 | 8 | DECLARE @key INT = 12 |
| 9 | DECLARE @msg NVARCHAR(MAX) = 'L2' | ||
| |
2.1 | 10 | |
| |
3.1 | 11 | BEGIN TRAN |
| 12 | IF EXISTS ( | ||
| 13 | SELECT * | ||
| 14 | FROM DBO.LOG2ENTITY WITH (UPDLOCK, SERIALIZABLE) | ||
| 15 | WHERE ID = @key | ||
| |
2.1 | 16 | ) |
| |
3.1 | 17 | BEGIN |
| 18 | UPDATE DBO.LOG2ENTITY | ||
| 19 | SET | ||
| |
4.1 | 20 | Message = @msg |
| |
3.1 | 21 | WHERE ID =@key |
| 22 | END | ||
| 23 | ELSE | ||
| 24 | BEGIN | ||
| |
4.1 | 25 | INSERT INTO DBO.LOG2ENTITY (Message) |
| |
3.1 | 26 | VALUES (@msg) |
| 27 | END | ||
| 28 | COMMIT TRAN | ||
| |
5.1 | 29 | |
| |
2.1 | 30 | {{/code}} |
| |
7.1 | 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) При необходимости обновляем строку. |