2016-12-06 84 views
1

我有一張競標拍賣表,對於某個拍賣的每個出價應該高於其他每個拍賣對象。 這怎麼辦?因爲我不知道如何使約束工作,所以我想過使用觸發器,但沒有發現任何類似的目標(我對sql很陌生)。對同一表格中的其他行執行強制約束

我的表創建SQL:

CREATE TABLE bid(
    id_auction NUMBER(10) NOT NULL, 
    username VARCHAR(20) NOT NULL, 
    amount FLOAT NOT NULL, 
    b_date DATE NOT NULL, 
    CONSTRAINT pk_bid PRIMARY KEY (id_auction, username, amount), 
    FOREING KEY (username) REFERENCES user(username), 
    FOREIGN KEY (id_auction) REFERENCES auction(id_auction) 

);

我不完全觸發:

CREATE OR REPLACE TRIGGER high_bid_trigger 
BEFORE INSERT 
ON bid 
DECLARE 
    highest_bid NUMBER; 
BEGIN 
    highest_bid := (SELECT min(amount) 
        FROM bid 
        WHERE username = :NEW.username 
        AND id_aution = :NEW.id_auction) 
    if highest_bid < :NEW:bid 

我使用的是Oracle數據庫。

+0

首先,可能會改變min的最大和擺脫「其中username」按您的要求加粗。其次,您可能需要使用RAISE_APPLICATION_ERROR。一旦你完成了這兩件事情,請包括解釋者在嘗試創建觸發器和測試時給出的信息。 –

回答

1

你可以用觸發器來做到這一點,我想。當您從觸發器中的相同表中獲取數據時,可能會遇到突變觸發器的問題。這些很難解決。

我不知道這是否可行,但可以通過存儲增量而不是絕對值來解決此問題。然後,您可以保證增量大於0:

constraint chk_t_increment check (increment > 0); 

但是,當您要查詢值時,這很混亂。

另一種選擇是在插入觸發器後使用將數據維護在另一個表中。所以,拍賣表會有一個當前最高出價的列。

然後,您可以在插入觸發器之前在中使用此值,其中舊值將被使用。

這種類型的問題是爲什麼喜歡包數據修改步驟到存儲過程,而不是處理它們通過直接調用update/insert/delete一個例子。一個存儲過程可以靈活地執行你想做的事情,而不需要涉及任何觸發器。

+0

我在答案中增加了一個附註:當幾個會話同時插入數據時,解決方案中任何觸發器都不兼容。 –

+0

第一個選項是不可能的,因爲增量不是針對欄目,而是針對每個auction_id的欄目。爲什麼具有觸發器的解決方案與多個會話不兼容? –

+0

關於在拍賣表中存儲最高出價的第二個理念:如果不是如何設置錯誤並停止插入? –

0

這是一個應用程序的工作,而不是數據庫。

0

杜杜說,這最好在應用程序級完成。

如果由於某種原因,您必須在數據庫中執行此操作,您最好的選擇可能是快速刷新提交的物化視圖。例如,該視圖可能包含嚴格大於最近出價金額的所有出價金額的計數,這些出價金額是通過基本表格按ID分組的。在這個物化視圖中,你可以有一個限制,即所有的值必須爲零。

每當嘗試「冒犯」插入時,都會試圖在實例化視圖中插入值1。這將被拒絕。這是你的約束!

https://asktom.oracle.com/pls/apex/f?p=100:11:0::::p11_question_id:4233459000346171405

0

我會做一個程序做到這一點:

-- Create Bid Table 
CREATE TABLE bid 
(
    bid_id  INTEGER 
    , bid_amount DECIMAL (6, 2) 
    , bidder  VARCHAR2 (30) 
); 

-- Use this procedure to make a bid 
CREATE OR REPLACE PROCEDURE make_bid (
    p_bid_id  IN bid.bid_id%TYPE 
    , p_bid_amount IN bid.bid_amount%TYPE 
    , p_bidder  IN bid.bidder%TYPE 
) 
AS 
    -- ********************************************************************** 
    -- Make Bid 
    -- Purpose: 
    -- Make a bid on an auction item 
    -- Arguments: 
    -- p_bid_id  - id of item being bid upon 
    -- p_bid_amount - amount of the bid 
    -- p_bidder  - account of the bidder 
    -- Notes: 
    -- Throws an exception if bid amount does not exceed previous bid 
    -- ********************************************************************** 
    l_max_previous_bid bid.bid_amount%TYPE; 
BEGIN 
    -- Coalesce is used to set previous bid to 0 if no bids have been made. 
    SELECT COALESCE (MAX (bid_amount), 0.0) 
     INTO l_max_previous_bid 
     FROM bid 
    WHERE bid_id = p_bid_id; 

    -- Throw an exception if bid does not exceed previous bid (or zero) 
    IF p_bid_amount <= l_max_previous_bid 
    THEN 
     raise_application_error (
      -20001 
      , 'Bid amount <= TO current bid amount' 
      || UTL_TCP.crlf 
      || RPAD ('BID_ID', 20) 
      || ': ' 
      || l_max_previous_bid 
      || UTL_TCP.crlf 
      || RPAD ('Bid Amount', 20) 
      || ': ' 
      || p_bid_amount 
      || UTL_TCP.crlf 
      || RPAD ('Exisiting Bid Amount', 20) 
      || ': ' 
      || l_max_previous_bid 
      || UTL_TCP.crlf 
      || RPAD ('Bidder', 20) 
      || ': ' 
      || p_bidder 
     ); 
    END IF; 

    -- if we got to here, everything is good 
    -- Update the record to the new bid 
    UPDATE bid 
     SET bidder = p_bidder, bid_amount = p_bid_amount 
    WHERE bid.bid_id = p_bid_id; 

     -- if zero rows were updated, there is no existing bid on the object 
     -- and we need to add a new value. 
    IF SQL%ROWCOUNT = 0 
    THEN 
     INSERT INTO brianl.bid (
        bid_id, bid_amount, bidder 
        ) 
      VALUES (p_bid_id, p_bid_amount, p_bidder); 
    END IF; 
END make_bid;