2010-12-03 46 views
2

我一直在修補這個問題一段時間,但沒有任何工作適合我。SQL Server 2008 - 使用本地變量進行INSERT和UPDATE觸發器

問題是爲order_details表創建INSERT和UPDATE觸發器(tr_check_qty),以僅允許庫存數量大於或等於訂單單位的產品訂單。

CREATE TRIGGER tr_check_qty 

ON order_details 
FOR insert, update 

AS 

DECLARE @stock int 
DECLARE @neworder int 
SELECT @stock = quantity_in_stock FROM products 
SELECT @neworder = quantity FROM inserted 

IF @neworder > @stock 

BEGIN 
PRINT 'NO WAY JOSE' 
ROLLBACK TRANSACTION 
END 

爲了測試這個觸發器,我們應該使用這個查詢:

UPDATE order_details 
SET quantity = 30 
WHERE order_id = '10044' 
AND product_id = 7 

查詢選擇一個只有28 quantity_in_stock,應觸發扳機的產物。但是我的觸發器不會觸發,它會成功更新表。

我不得不懷疑,觸發器不喜歡局部變量,所以我嘗試不使用局部變量:

(SELECT quantity FROM inserted) > (SELECT quantity_in_stock FROM products) 

但是,這給了我一個錯誤。

任何幫助,將不勝感激!

+0

感謝您的幫助@Dog Ears和@Martin!你是對的,這是一個任務:p但希望有一天我會達到一個水平,我可以爲他人的家庭作業給出我自己的答案。 :D哦,是的,我有觸發器工作!我在@Dog Ears的建議中提到加入產品並插入表格:DECLARE \t @stock int DECLARE \t @neworder \t int SELECT \t @stock = products.quantity_in_stock從\t產品插入WHERE products.product_id = inserted.product_id SELECT \t @neworder = inserted.quantity從\t插入觸發器工作!再次感謝您的回覆!^_^ – Magi604 2010-12-04 07:37:05

回答

1
  1. 您假定只有一行插入或更新。

  2. quantity_in_stock FROM products沒有謂詞 - 大概需要檢查插入的productid的庫存水平?如果是這樣的products表的結構是什麼? (目前@stock會從任意行的products表格採用多行被分配一個值。

  3. 這下快照隔離將無法正常工作。

爲了繞開#1和#2你需要使用productid加入inserted表到products表或什麼,看看是否存在任何行,其中inserted.quantity > products.quantity_in_stock

有關#3的一些想法閱讀the discussion here

0

,您的觸發已經不遠了,但實際上,你可以使用和INSTEAD OF觸發器

創建測試數據

create table product (productId int identity(1,1) constraint PK_product_productId primary key clustered, quantity_in_stock int) 
create table order_detail ( order_id int 
         ,productId int constraint FK_order_product_productId foreign key references product (productId) 
         ,quantity int not null) 
set identity_insert product on 
insert into product (productId, quantity_in_stock) values (1, 100), (2, 25) , (3, 2); 

這「工作」(在長期的lossest感) 考慮到馬丁的評論爲quantity_in_stock需要確定。

CREATE TRIGGER tr_check_qty 
ON order_detail 
FOR insert, update AS 

DECLARE @stock int 
DECLARE @neworder int 
SELECT @stock = quantity_in_stock 
     From product 
     Where productid = (select productid from inserted) 
SELECT @neworder = quantity FROM inserted 

IF @neworder > @stock 

BEGIN 
PRINT 'NO WAY JOSE' 
ROLLBACK TRANSACTION 
END 

這些現在都按預期工作......

INSERT order_detail (order_id, productId, quantity) 
values 
(10044, 1, 30) -- works as stock is 100 
,(10044, 3, 1) 

insert order_detail (order_id, productId, quantity) 
values 
    (10044, 1, 130) /* fails (CORRECTLY) WITH Msg 3609, Level 16... (transacted ended in the trigger..) */ 

/* this should work... */ 
UPDATE order_detail 
SET quantity = 30 
WHERE order_id = 10044 
AND productid = 1 

/* this should fail.. */ 
UPDATE order_detail 
SET quantity = 3000 /*< not enough stock. */ 
WHERE order_id = 10044 
AND productid = 1 

,並解決馬丁斯第一點這種方式較好:

CREATE TRIGGER tr_check_qty 
ON order_detail 
FOR insert, update AS 

DECLARE @stock int 
DECLARE @neworder int 

if(exists(select * 
      from inserted i join product p on i.productId = p.productId 
      where i.quantity > p.quantity_in_stock)) 
begin 
PRINT 'NO WAY JOSE' 
ROLLBACK TRANSACTION 
End 
+0

看起來更好!實際上,我發現的多行插入的另一個問題是,它們可能包含需要分組的同一產品的多行。例如`選擇i.p​​roductid從插入我加入產品p在i.productid = p.productid組由i.productid具有SUM(i.quantity)> p.quantity_in_stock` – 2010-12-04 01:15:49

0

另一種解決方案是使用的INSTEAD OF觸發器,這樣的事情:

Create Trigger TR_Check_Qty 
ON order_detail 
INSTEAD OF insert AS 

insert into order_detail (order_id, productId, quantity) 
    select i.order_id, i.productId, i.quantity 
    from inserted i inner join product p on i.productId = p.productId 
    where i.quantity <= p.quantity_in_stock 

這觸發行爲與其他建議不同!這個觸發器會插入完成的訂單,並忽略超過庫存水平的訂單,這可能不是必需的[事實上它可能不是在大多數情況下;你的應用程序想知道什麼時候訂單還沒有保存到數據庫!!!]

注意這只是一個插入,你需要創建一個不同的觸發器更新爲'插入'值將需要更新不插入。

此外,還有其他一些考慮因素超出了這個問題的範圍。您應該在插入訂單時降低庫存水平,並且您應該可能想要處理爲相同產品插入多個明細行的情況。