У меня есть пользовательская таблица, в которой я хочу создать условие, если количество запасов >= source.Qty, а затем вычесть еще raiserror('Qty not enough', 16, 1)
Это мой код
MERGE Stock AS TARGET
USING @InvoiceLines AS SOURCE
ON (TARGET.ProductID = SOURCE.ProductID AND TARGET.Qty >= SOURCE.Qty)
WHEN MATCHED THEN
UPDATE
SET Qty = TARGET.Qty - SOURCE.Qty;
@DaleK вычитает, даже если акции 0 будут равны -1. Я хочу поднять ошибку, если условие не соответствует.
Пожалуйста, отредактируйте свой вопрос, чтобы уточнить это.
Вы можете проверить свою таблицу на наличие строк с количеством меньше нуля после слияния и, если таковые имеются, откатить транзакцию и выдать ошибку.
Обратите внимание: не используйте raiserror, используйте throw
@DaleK может редактировать мой код и показывать правильный синтаксис.
@DaleK Я не знаю правильного синтаксиса для выдачи исключения, если Qty меньше, можете ли вы внести изменения в мой код
Обратитесь к документации Используйте THROW, чтобы вызвать исключение
@Squirrel, проблема с моим (синтаксисом слияния), когда он не совпадает, он позволяет только вставку, обновление, удаление, я не могу сделать исключение throw
@Squirrel, я пробовал много раз, можешь ли ты отредактировать синтаксис моего кода в соответствии с моими потребностями?
MERGE ...... IF EXISTS (SELECT * FROM Stock WHERE Qty < 0) THROW ......
Почему Merge
, когда достаточно простого Update
?
Я решил, проверив @@Rowcount, если 0 означает, что строка не затронута, часть моего кода
BEGIN
MERGE Stock AS TARGET
USING @InvoiceLines AS SOURCE
ON (TARGET.ProductID = SOURCE.ProductID AND TARGET.Qty >= SOURCE.Qty )
WHEN MATCHED THEN
UPDATE SET Qty =TARGET.Qty - SOURCE.Qty;
IF @@ROWCOUNT=0
RAISERROR('Qty not Enough', 16, 2)
END
BEGIN CATCH
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE()
,@xstate = XACT_STATE()
IF @xstate = -1
rollback;
IF @xstate = 1 and @trancont = 0
rollback
IF @xstate = 1 and @trancont > 0
rollback transaction mytran
--IF @@TRANCOUNT > 0
--BEGIN
RAISERROR(@message, 16, 1)
-- ROLLBACK
--END
END CATCH
Используйте THROW
, а не RAISERROR
, да и зачем бросать только для того, чтобы поймать, можно условно откатиться без ловли
Кроме того, если нужно изменить более одной строки, это вообще не будет работать.
Похоже, вам просто нужен IF EXISTS
. Просто проверить @@ROWCOUNT
недостаточно, если требуется изменить более одной строки.
Также обратите внимание:
UPDLOCK
или SERIALIZABLE
, чтобы обеспечить правильную блокировку.SET XACT_ABORT ON
, чтобы гарантировать правильные откаты.THROW
, а не RAISERROR
, так как это лучше учитывает откаты.ON
в MERGE
должно быть только условием соединения, все остальные условия должны находиться в CTE или в предложении WHEN MATCHED THEN
.UPDATE
.SET XACT_ABORT, NOCOUNT ON;
BEGIN TRAN;
IF EXISTS (SELECT 1
FROM Stock AS s WITH (UPDLOCK)
JOIN @InvoiceLines AS il
ON s.ProductID = il.ProductID
WHERE s.Qty < il.Qty
)
THROW 50001, N'Qty not Enough', 1;
UPDATE s
SET Qty -= il.Qty
FROM Stock AS s
JOIN @InvoiceLines AS il ON il.ProductID = s.ProductID;
COMMIT;
@да, я проверил свой старый ответ, когда в одном из продуктов осталось количество, все еще возвращается 1 ROWCOUNT, я сделал ваш ответ, и он работает отлично, большое спасибо
Пожалуйста, предоставьте минимально воспроизводимый пример с данными образца и желаемыми результатами.