2011-12-06 32 views
2

對於這個令人困惑的問題,文字牆和可怕的觸發器,我提前表示歉意。我正在爲一家零售店設計一個小型數據庫,在店內接受訂單,然後從現場倉庫/庫房交付產品。Oracle觸發從產品中刪除庫存數量並添加到訂單行

現在訂單實體與一個order_line實體有一對多的關係,而這個實體又與產品(它本身存儲在庫存中)有多對一的關係。 order_line實體是鏈接實體並且解決了多對多關係,所以這一切都很好。只是爲了澄清,每個產品都是一個order_line。

我想要做的是創建一個order_line(它有一個數量屬性),我希望觸發器首先檢查相應的產品是否有足夠的庫存(因此如果數量爲3,庫存必須至少爲3) ,否則它必須拋出一個錯誤。

如果成功,我希望它相應地更新數量和庫存屬性。我還希望它爲order_line添加一個小計值(我尚未嘗試此操作),然後可以用它來計算訂單實體中的總值。

所以在這個階段我正在尋找一些指導,因爲我現在對此很困惑。

CREATE OR REPLACE TRIGGER check_order_line 
BEFORE INSERT OR UPDATE ON order_line 

for each row 
BEGIN 
select order_line.quantity, products.stock from order_lines right join products on  order_line.product_no=products.product_no; 
if(order_line.quantity>products.stock) then 
RAISE_APPLICATION_ERROR(-20103, 'Insufficient Stock'); 
ELSE 
products.stock := products.stock - quantity; 
dbms_output.put('Successful'); 
END IF; 
END; 
. 
run 

錯誤我得到:

2/1  PL/SQL: SQL Statement ignored 
2/49  PL/SQL: ORA-00942: table or view does not exist 
3/1  PL/SQL: Statement ignored 
3/15  PLS-00357: Table,View Or Sequence reference 'ORDER_LINE.QUANTITY' 
    not allowed in this context 

我已經試過什麼:

  • 我不知道前兩個錯誤;有問題的表是 絕對稱爲order_line,也許我錯過了一些明顯的東西。
  • 我也試過聲明變量的products.stock和order_line 數量來解決上一個錯誤 - 這編譯IIRC但不 實際工作,因爲我猜它不是更新表。
  • 我並不擔心其他操作,我可能需要更新 表語句,但現在我只關注讓 觸發條件起作用。
  • 如果任何人可以指出我在正確的 方向,並指出任何有趣的錯誤,我會很感激。

    非常感謝您的寶貴時間,我爲您的眼睛疤痕引發了這種巨大的恐慌表示歉意。

+0

這是什麼'run'命令在最後?您使用哪個工具來執行CREATE TRIGGER? –

回答

3

把一個約束上products.stock執行值爲> -1:

ALTER TABLE products add CONSTRAINT has_stock CHECK (stock >-1); 

然後執行updateinsert作爲單個事務。

UPDATE product SET products.stock = products.stock - quantity_required 
WHERE product_id=id_of_product 

INSERT INTO order_line ............... 

COMMIT; 

如果沒有足夠的庫存,交易將總是失敗,並且您不會遇到與觸發器相關聯的問題。

UPDATE product SET products.stock = products.stock - quantity_required 
WHERE product_id=id_of_product 
RETURNING products.value INTO v_product_cost 

假設你沒有股票價格在這一點上,你可以用你的update(需要聲明變量v_product_cost保存的值)例如RETURNING條款得到它然後,您可以在隨後的插入中使用此值。

+0

嗨凱文,我會添加約束,謝謝你。這看起來像一個簡單的基礎級解決方案,可以很好地工作。明天我會嘗試更新。感謝您的迴應,我非常感謝您的幫助。 –

1
  1. 最後的run命令沒有意義。這是SQL Server語法。
  2. 在您的查詢中,您引用了表ORDER_LINES(複數)。但觸發器在表ORDER_LINE(單數)上定義。我假設你沒有ORDER_LINEORDER_LINES表,所以我希望你希望你的查詢引用ORDER_LINE表。
  3. 在表A中定義的行級觸發器不能在通用查詢表A中。因此,由於您的觸發器是在ORDER_LINE上定義的,因此它無法查詢ORDER_LINE。看起來你真的只是想要關於引起觸發器觸發的行的信息,所以你實際上不需要加入ORDER_LINE表。您只需引用:NEW記錄中的屬性即可。
  4. A SELECT PL/SQL中的語句需要對結果做些什麼。據推測,你的意圖是做一個局部變量SELECT ... INTO
  5. 如果你想更新PRODUCTS表,你需要做一個實際的UPDATE

把所有一起,我的猜測是,你想創建一個觸發器,它看起來像

CREATE OR REPLACE TRIGGER check_order_line 
    BEFORE INSERT OR UPDATE ON order_line 
    for each row 
DECLARE 
    l_current_stock products.stock%type; 
BEGIN 
    select products.stock 
    into l_current_stock 
    from products 
    where product_no = :new.product_no; 
    if(:new.quantity > l_current_stock) then 
    RAISE_APPLICATION_ERROR(-20103, 'Insufficient Stock'); 
    else 
    update products 
     set stock := stock - :new.quantity 
    where product_no := :new.product_no; 
    end if; 
END; 

之所以這麼說,但是,觸發一般將不正確的方法解決這類問題。從維護的角度來看,如果沒有別的,使用存儲過程PROCESS_ORDER插入所有的ORDER_LINE行並更新所有PRODUCTS行將更容易跟蹤和調試。嵌入的業務邏輯越多,觸發應用程序的流程就越困難,越容易結束,因爲這些更新幾乎不可能消除。

另外,請注意在多用戶系統中會發生什麼情況。會話A可以查詢PRODUCTS表並查看5的STOCK並接受4單位該產品的訂單。但在會話A發出提交之前,會話B還查詢PRODUCTS表的同一行,看到相同的STOCK爲5,並接受3個單元的訂單。會話B的UPDATE語句將阻塞,直到會話A提交。但是如果A提交併且B提交,那麼兩個訂單都將被輸入並且PRODUCTS表將顯示爲-2的STOCK。這就是爲什麼你需要的約束,凱文建議

ALTER TABLE products 
    ADD CONSTRAINT chk_positive_stock CHECK(stock >= 0); 
+0

嗨Justin,感謝您發現Order_lines錯字 - 您說得對,我只在這個系統中使用order_line。關於第3點,我明白你的意思,我想我會得到一個表格變異錯誤,所以我會研究你的建議。第4點:這是有道理的。 不幸的是,課程作業規範需要三個觸發器,沒有標記被授予程序(這似乎很愚蠢),這是我的第三個觸發器。如果是你,你會不會打擾這個功能的觸發器(如果程序不是一個選項)?你給的理由讓我覺得我應該看看另一個想法。 –

相關問題