对同一个表中的其他行强制执行约束

时间:2016-12-06 19:50:47

标签: sql oracle plsql triggers

我有一张竞标拍卖的表格,而某些拍卖的每个竞标价格应该高于其他拍卖的竞标。 如何才能做到这一点?由于我不知道如何使约束工作,我考虑使用触发器,但没有找到任何具有类似目标(我对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数据库。

4 个答案:

答案 0 :(得分:1)

我认为你可以使用触发器来做到这一点。当您从触发器中的同一个表中获取数据时,您可能会遇到变异触发器的问题。这些很难解决。

我不知道它是否可行,但你可以通过存储增量而不是绝对值来解决这个问题。然后,您可以保证增量大于0:

entry

但是,当您想要查询值时,这很麻烦。

另一种选择是在插入触发器后使用来维护另一个表中的数据。因此,拍卖表将包含当前最高出价的列。

然后,您可以在插入触发器之前的中使用此值,其中将使用旧值。

这类问题是我喜欢将数据修改步骤包装到存储过程中的一个示例,而不是通过直接调用constraint chk_t_increment check (increment > 0); / update / insert来处理它们。存储过程可以灵活地执行您想要执行的操作而不需要触发器。

答案 1 :(得分:0)

这是应用程序的作业,而不是数据库的作业。

答案 2 :(得分:0)

正如Dudu所说,最好在应用程序级别完成。

如果由于某种原因你必须在数据库中执行此操作,那么最好的选择可能是在提交时快速刷新的物化视图。例如,该视图可以包含所有出价金额的计数,该出价金额严格大于最近的出价金额(按ID分组)。在此物化视图中,您可以拥有一个约束,即所有值必须为零。

每当冒犯&#34;冒犯&#34;尝试插入时,将尝试在物化视图中插入值1。这将被拒绝。这是你的约束!

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

答案 3 :(得分: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;