SQL触发器插入问题

时间:2018-06-07 10:20:10

标签: sql sql-server triggers

我想制作一个触发器,我可以检查产品0的库存中的值是否为。 然后触发器应该使值为1。

我的触发器

CREATE TRIGGER [IfStockIsNull]
ON [dbo].[Products]
FOR DELETE, INSERT, UPDATE
AS
BEGIN

if [Products].Stock = 0
    UPDATE [Products] SET [Stock] = 1
    FROM [Products] AS m
    INNER JOIN inserted AS i
    ON m.ProductId = i.ProductId;
ELSE
    raiserror('Niks aan het handje',10,16);
END

我收到了错误:

Altering [dbo].[IfStockIsNull]...
(53,1): SQL72014: .Net SqlClient Data Provider: Msg 4104, Level 16, State 1, 
Procedure IfStockIsNull, Line 7 The multi-part identifier "Products.Stock" 
could not be bound.
(47,0): SQL72045: Script execution error.  The executed script:
ALTER TRIGGER [IfStockIsNull]
ON [dbo].[Products]
FOR DELETE, INSERT, UPDATE
AS BEGIN
       IF [Products].Stock = 0
           UPDATE [Products]
           SET    [Stock] = 1
           FROM   [Products] AS m
                  INNER JOIN
                  inserted AS i
                  ON m.ProductId = i.ProductId;
       ELSE
           RAISERROR ('Niks aan het handje', 10, 16);
   END

An error occurred while the batch was being executed.

也许你们可以帮助我?

2 个答案:

答案 0 :(得分:3)

您尝试在此处运行的许多问题和惊喜。但基本上,当您处理时,不要尝试运行程序步骤。 inserted可以包含0,1或多个行,因此您在IF中询问哪个行的股票?

最好在WHERE子句中处理它:

CREATE TRIGGER [IfStockIsNull]
ON [dbo].[Products]
FOR INSERT, UPDATE --Removed DELETE, because ?!?
AS
BEGIN

    UPDATE [Products] SET [Stock] = 1
    FROM [Products] AS m
    INNER JOIN inserted AS i
    ON m.ProductId = i.ProductId;
    WHERE m.Stock = 0
    --Not sure what the error is for - the above update may have updated
    --some number of rows, between 0 and the number in inserted.
    --What circumstances should produce an error then?
END

UPDATE 的简单演示脚本正确定位inserted中匹配的行:

declare @t table (ID int not null, Val int not null)
insert into @t(ID,Val) values (1,1),(2,2),(3,3)
update
    @t
set
    Val = 4
from
    @t t
        inner join
    (select 2 as c) n
        on
            t.ID = n.c

select * from @t

显示只更新ID 2的行。

即使是Microsoft的自己的UPDATE ... FROM syntax示例也使用了Gordon声称不起作用的UPDATE <table> ... FROM <table> <alias> ...语法:

USE AdventureWorks2012;  
GO  
UPDATE Sales.SalesPerson  
SET SalesYTD = SalesYTD + SubTotal  
FROM Sales.SalesPerson AS sp  
JOIN Sales.SalesOrderHeader AS so  
    ON sp.BusinessEntityID = so.SalesPersonID  
    AND so.OrderDate = (SELECT MAX(OrderDate)  
                        FROM Sales.SalesOrderHeader  
                        WHERE SalesPersonID = sp.BusinessEntityID);  
GO  

此示例确实有一个问题,在下面进一步说明但是与“其他表中的多个匹配行只会导致单个更新”的缺陷是任何使用{{1应该让自己意识到。

答案 1 :(得分:1)

如果你想在任何行不好的情况下停止插入,那么在进行更改之前执行

ALTER TRIGGER [IfStockIsNull] ON [dbo].[Products]
    FOR INSERT, UPDATE  -- DELETE is not really appropriate
AS BEGIN
   IF (EXISTS (SELECT 1
               FROM Products p JOIN
                    inserted i
                    ON m.ProductId = i.ProductId
               WHERE p.Stock = 0
              )
      )
    BEGIN
        RAISERROR ('Niks aan het handje', 10, 16);
    END;
     UPDATE p
         SET Stock = 1
         FROM Products p INNER JOIN
              inserted AS i
              ON p.ProductId = i.ProductId;
END;

注意:

  • IF中的比较检查Product行中是否有0行。如果是,则回滚整个事务。
  • 你可能会抱怨你不能拒绝一行。但这就是交易的运作方式。如果INSERT中的任何行失败,则会回滚整个INSERT,而不仅仅是一行。
  • UPDATE不正确,因为Products子句和FROM子句中有UPDATE。您需要使用第一个别名。