2011-12-09 54 views
1

我仍在爲一家小型零售商店(一個場景,很幸運!)工作在這個數據庫上,目前正試圖用觸發器解決這個問題。Oracle - ORA-01422:精確提取返回的行數多於請求的行數

相關實體爲客戶,付款和訂單。支付是另外兩個之間的鏈接實體,因此一個客戶可以進行多筆付款,一個訂單可以有多筆付款(不常見但仍然可行),並且這一切都很好。

觸發:

CREATE OR REPLACE TRIGGER Check_Payment_Status 
BEFORE UPDATE OF Order_Status ON Customer_Order 

for each row 
    DECLARE paymentStatus payment.payment_status%type; 
    BEGIN 

    select payment.payment_status into paymentStatus 
    from payment 
    where order_no = :new.order_no; 

    IF (paymentStatus ='Failed' OR paymentStatus IS NULL) then 
     RAISE_APPLICATION_ERROR(-20103, 'The full payment has not been made so the order cannot be  processed further until then.'); 
     update customer_order set order_status='Delayed' where order_no= :new.order_no; 
    END IF; 

    IF (paymentStatus ='Successful') then 
     update payment set payment_date=SYSDATE where order_no= :new.order_no; 
    END IF; 


    END; 
. 
run 

它目前工作好。基本上,在客戶的訂單可以被標記爲「分派」之前,付款狀態必須是「成功」的。如果它爲空或「失敗」,觸發器將會像「哦,不,你不! (但用更正式的話來說),這是按照預期工作的。但是,如果有人應用業務規則「訂單可以有多筆付款」,則觸發器需要檢查所有相關付款,這是我收到此錯誤的地方,因爲SELECT INTO聲明打算僅返回一行。

我已經閱讀了一些光標,但我想我在這裏有點太過分了 - 有人會提出一些解決方案嗎?

+0

如果您只是根據觸發器的名稱檢查付款狀態,爲什麼要在此處更新payment_date?這在這裏似乎不合適 - 您不會在您將payment_status設置爲成功的同一時間更新付款日期嗎? – DCookie

回答

9

那麼,如果一個訂單可以有多個付款,你如何決定是否全額付款?據推測,每筆付款都有一筆款項,訂單上有一筆到期的款項,因此您需要檢查是否已支付全款。在我看來,您可以通過獲得所有成功付款的總和,然後將其與應付總額進行比較來完成此操作。基本的查詢是:

SELECT SUM(payment_amount) 
    INTO total_payment_amount 
    FROM payment 
    WHERE order_no = :new.order_no 
     AND payment_status = 'Successful'; 
+0

+1你在這裏比我快 –

8

在一般筆記,你有很多的應用程序級的邏輯捆綁到一個觸發,這將讓你進入了很多麻煩的道​​路,因爲你不瞭解您的相關表格中何時和爲什麼更新了值。

Dave Costa對處理付款有一個很好的建議,我會創建一個或多個相關的PL/SQL包,其中包含明確編寫的函數和過程以處理您要在此執行的應用程序級邏輯觸發。

觸發器應該很少使用 - 通常是在從序列中設置主鍵或審計對錶的訪問時。

4

我知道這是一個老問題,但今天在客戶端生產數據庫中出現類似問題。有時可以通過主鍵(可能是序列號)按降序排列並使用「rownum = 1」進行排序。當然,你應該找出爲什麼你有多個符合條件的記錄,並修復了允許它的應用程序中的錯誤。

相關問題