SQL Server UPDATE触发数量检查错误

时间:2018-03-24 22:29:58

标签: sql sql-server tsql triggers

我尝试创建一个触发器,如果​​数量大于orderdetails表中的unitsinstock,则会阻止用户更新products表中的数量

我是新手,并尝试阅读我在微软的T-SQL文档here中可以找到的内容,但没有发现它太有用了。

这是我得到的错误:

  

Msg 512,Level 16,State 1,Procedure tr_check_qty,Line 281 [Batch Start Line 0]
  子查询返回的值超过1。当子查询遵循=,!=,<,< =,>,> =或子查询用作表达式时,不允许这样做。

有人有什么建议吗?

CREATE TRIGGER tr_check_qty
ON orderdetails
FOR UPDATE
AS
    DECLARE @prod_id INT

    SELECT @prod_id = productid
    FROM inserted

    IF (SELECT products.UnitsInStock
        FROM products
        WHERE products.productid = @prod_id) >= (SELECT orderdetails.quantity
                                                 FROM orderdetails
                                                 WHERE orderdetails.productid = @prod_id)
    BEGIN
        ROLLBACK TRANSACTION
        PRINT 'Not enough units in stock.'
    END 
GO

2 个答案:

答案 0 :(得分:0)

消息很清楚,你的一个选择会返回多于1个值,因此无法进行比较,因为它不知道必须比较哪些值。

这是您要编写的代码(您只需要为更新的orderdetail检索产品数量):

create trigger tr_check_qty
ON orderdetails
FOR UPDATE
AS
DECLARE @orderdetail_id int
DECLARE @prod_id int
select @orderdetail_id = orderdetailid, @prod_id = productid
FROM inserted
IF(
    select UnitsInStock
    from products
    where productid = @prod_id
)
>= 
(
    select quantity
    from orderdetails
    where orderdetailid = @orderdetail_id and productid = @prod_id
)
BEGIN
ROLLBACK TRANSACTION
PRINT 'Not enough units in stock.'
END 
GO

这仅在您逐个修改记录时才有效(因此插入的虚拟表只有一条记录)。但是迟早你会尝试在一条指令上更新几个orderdetails,并且你的触发器不会遍历每个更新的产品。为此,您需要一个光标。

我还用raiserror替换了你的回滚(也回滚了事务)。

create trigger tr_check_qty
ON orderdetails
FOR UPDATE
AS
DECLARE @orderdetail_id int
DECLARE @prod_id int
DECLARE UpdatedProducts CURSOR FOR select orderdetailid, productid from inserted
OPEN UpdatedProducts
FETCH NEXT FROM UpdatedProducts INTO @orderdetail_id, @product_id
WHILE @@fetch_status = 0
BEGIN
  IF(
      select UnitsInStock
      from products
      where products.productid = @prod_id
  )
  >= 
  (
      select quantity
      from orderdetails
      where orderdetailid = @orderdetail_id and productid = @prod_id
  )
  BEGIN
    CLOSE UpdatedProducts
    DEALLOCATE UpdatedProducts
    RAISERROR('Not enough units in stock.', 20, -1)
  END
  @FETCH NEXT FROM UpdatedProducts INTO @orderdetail_id, @product_id
END
CLOSE UpdatedProducts
DEALLOCATE UpdatedProducts
GO

但是,如果您直接将products表连接到插入的虚拟表,那么您可以构建一个更简单的触发器,对更新的每一行执行相同的检查。

create trigger tr_check_qty
ON orderdetails
FOR UPDATE
AS
IF exists(select *
          from inserted
               inner join products on products.productid = inserted.productid
          where inserted.quantity > products.UnitsInStock)
begin
    raiserror('Not enough units in stock.', 20, -1)
end
GO 

答案 1 :(得分:0)

谢谢@Marc Guillot,我使用下面的代码使触发器工作,以满足问题中的两个更新(允许1个,不1个)。

.env