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,它还会删除插入的行吗?”假设您
抛出一个严重程度足够高的错误,并自动处理回滚,或者在
中尝试…捕获
是。但是您在这里提出的问题会导致更多问题;您的想法中存在一些缺陷。