INSERT后的SQL触发器不在我的IF语句之后,也不删除新行
我触发了一个触发器,每次我在“发票”表中插入时,它都会检查数量(订购金额)是否高于其他表中的可用库存金额。 如果数量较高,则应打印库存不足,并删除新插入的行。 它根本没有这样做。它只插入行,不打印任何消息INSERT后的SQL触发器不在我的IF语句之后,也不删除新行,sql,sql-server,tsql,triggers,Sql,Sql Server,Tsql,Triggers,我触发了一个触发器,每次我在“发票”表中插入时,它都会检查数量(订购金额)是否高于其他表中的可用库存金额。 如果数量较高,则应打印库存不足,并删除新插入的行。 它根本没有这样做。它只插入行,不打印任何消息 create trigger testtrigger on invoices after insert as begin declare @productID int declare @quantity int declare @stock int select @stock = stock
create trigger testtrigger
on invoices
after insert
as
begin
declare @productID int
declare @quantity int
declare @stock int
select @stock = stock from Products where ProductID = @productID
select @productID = productid from inserted;
select @quantity = Quantity from inserted;
if @productID not in (1, 2, 3, 4, 5, 6)
begin
if @quantity > @stock
begin
Print N'Not enough Stock. Current Stock: ' + @stock
delete from Invoices where InvoiceID = @@IDENTITY
end
end
end
前6个产品不是有库存量的东西,它是一个服务,所以我不想在这些产品ID上的订单上触发它
这只是检查更多内容的更大If-Else的一部分(例如,如果数量小于库存,则使用else语句更新剩余库存,但这是触发器的开始,它不起作用,因此我想从这里开始。对于任何t-SQL,包括触发器,您需要进入基于集合的操作的思维模式,而不是过程性的RBAR(逐行)操作
触发器为您提供了应该像使用任何其他表一样使用的触发器,即基于集合的方式
正如注释中指出的,触发器需要尽可能快地运行,因为它们在处理过程中持有锁
create trigger testtrigger
on invoices
after insert
as
begin
set nocount, xact_abort on;
-- Check if *any* of the inserted products exceeds the current stock levels
-- Taking into account the possibility of the same product occurring in multiple invoices
-- You could use similar logic to capture the products for which the stock level was exceeded
-- However its very complex to only rollback those which are wrong.
-- Really this should be your last line of defence, only used to ensure database integrity, so you should be checking stock levels before now
-- And therefore it shouldn't matter rolling everything back
if exists (
select 1
from Inserted I
inner join Products P on P.ProductId = I.productId
where productID not in (1, 2, 3, 4, 5, 6)
group by P.Id, P.Stock
having sum(I.Quantity) > P.Stock;
) begin
-- If you want to do something in your calling code you need to throw an exception. Printing is only relevent while testing in SSMS.
-- Throwing an exception will also roll back the transaction
throw 51000, 'Not enough Stock.', 0;
end;
end;
您的触发器存在严重缺陷;它假定插入的
仅包含1行。这根本不是真的。而且,通常情况下,您不会删除该行,并且打印信息消息,您会抛出一个错误。如果为同一产品插入2行,会发生什么?如果其他选项卡le的值为20
,插入的两行的值均为15
,则两行的值均小于20
,但是,您肯定没有30
库存。您可能会认为另一个表的(库存?)列应该同时更新。如果我抛出而不是删除,它还会删除插入的行吗?我不确定如何更改它以适应批量插入:/是否有办法让它逐行读取插入内容?“有办法让它逐行读取插入内容吗?”不要这样做,触发器对DML语句的影响应该尽可能小;在插入的数据中循环将对性能造成严重影响。“如果我使用throw而不是delete,它还会删除插入的行吗?”假设您抛出一个严重程度足够高的错误,并自动处理回滚,或者在中尝试…捕获是。但是您在这里提出的问题会导致更多问题;您的想法中存在一些缺陷。