Мне нужно написать хранимую процедуру T-SQL, которая обновляет строку в таблице. Если строка не существует, вставьте ее. Все эти шаги обернуты транзакцией.
Это для системы бронирования, поэтому она должна быть атомарной и надежной . Он должен вернуть значение true, если транзакция была совершена и рейс забронирован.
Я новичок в T-SQL , и не уверен, как его использовать @@rowcount
. Это то, что я написал до сих пор. Я на правильном пути? Я уверен, что это простая проблема для вас.
-- BEGIN TRANSACTION (HOW TO DO?)
UPDATE Bookings
SET TicketsBooked = TicketsBooked + @TicketsToBook
WHERE FlightId = @Id AND TicketsMax < (TicketsBooked + @TicketsToBook)
-- Here I need to insert only if the row doesn't exists.
-- If the row exists but the condition TicketsMax is violated, I must not insert
-- the row and return FALSE
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO Bookings ... (omitted)
END
-- END TRANSACTION (HOW TO DO?)
-- Return TRUE (How to do?)
sql
sql-server
sql-server-2008
tsql
Whymarrh
источник
источник
Ответы:
Посмотрите на команду MERGE . Вы можете сделать
UPDATE
,INSERT
иDELETE
в одном заявлении.Вот рабочая реализация по использованию
MERGE
- она проверяет, заполнен ли полет перед обновлением, иначе делает вставку.
А потом ...
источник
Я предполагаю одну строку для каждого полета? Если так:
Я предполагаю, что я сказал, так как ваш способ действий может перебить рейс, так как он вставит новый ряд, когда максимум 10 билетов, а вы бронируете 20.
источник
BEGIN TRAN ... COMMIT
уровне изоляции по умолчанию не решит проблему. ОП уточнил, что атомные и надежные требования. Ваш ответ не может решить эту проблему в любой форме или форме.IF EXISTS (SELECT * FROM Bookings (UPDLOCK, HOLDLOCK) WHERE FLightID = @Id)
?Пропускать намеки на блокировку строк, блокировку строк и блокировку при тестировании на наличие строки.
Подсказка при обновлении заставляет запрос принять блокировку обновления для строки, если она уже существует, не позволяя другим транзакциям изменять ее, пока вы не подтвердите или не откатитесь.
Подсказка удержания заставляет запрос принять блокировку диапазона, не позволяя другим транзакциям добавлять строку, соответствующую критериям вашего фильтра, пока вы не подтвердите или не откатитесь.
Подсказка о блокировке строки вынуждает детализацию блокировки на уровень строки вместо уровня страницы по умолчанию, поэтому ваша транзакция не будет блокировать другие транзакции, пытающиеся обновить несвязанные строки на той же странице (но помните о компромиссе между уменьшением конкуренции и увеличением накладные расходы на блокировку - вы должны избегать принятия большого количества блокировок на уровне строк в одной транзакции).
См. Http://msdn.microsoft.com/en-us/library/ms187373.aspx для получения дополнительной информации.
Обратите внимание, что блокировки воспринимаются как выполняемые операторы - вызов метода begin tran не дает вам иммунитета против другой транзакции, накладывающей блокировки на что-либо до того, как вы доберетесь до нее. Вы должны попытаться использовать свой SQL-код для удержания блокировок в кратчайшие сроки, совершая транзакцию как можно скорее (запоздайте поздно, выпустите раньше).
Обратите внимание, что блокировки на уровне строк могут быть менее эффективными, если ваш PK является bigint, так как внутреннее хеширование в SQL Server вырождено для 64-битных значений (разные значения ключа могут хешироваться с одним и тем же идентификатором блокировки).
источник
exists
проверки без подсказок блокировки.Я пишу свое решение. мой метод не стоит «если» или «слить». Мой метод прост.
Например:
Объяснение:
(1) ВЫБЕРИТЕ col1, col2 ОТ ИМЕНИ TableName, ГДЕ col1 = @ par1 И col2 = @ par2 Выбирает из найденных значений TableName
(2) SELECT @ par1, @ par2, ГДЕ НЕ СУЩЕСТВУЕТ. Требуется, если не существует, из (1) подзапроса.
(3) Вставляет в TableName (2) значения шага
источник
Я наконец смог вставить строку при условии, что она еще не существует, используя следующую модель:
который я нашел в:
http://www.postgresql.org/message-id/87hdow4ld1.fsf@stark.xeocode.com
источник
Это то, что я только недавно должен был сделать:
источник
Вы можете использовать функцию слияния для достижения. В противном случае вы можете сделать:
источник
Полное решение приведено ниже (включая структуру курсора). Большое спасибо Кассиусу Поркусу за
begin trans ... commit
код, опубликованный выше.источник
источник
источник
Лучший подход к этой проблеме - сначала сделать столбец базы данных УНИКАЛЬНЫМ.
ALTER TABLE table_name ADD UNIQUE KEY
THEN INSERT IGNORE INTO table_name
значение не будет вставлено, если оно приведет к дублированию ключа / уже существует в таблице.источник