【问题标题】:Is this possible in Oracle/Sql?这在 Oracle/Sql 中可能吗?
【发布时间】:2012-01-15 03:35:33
【问题描述】:

我有两张桌子:

CREATE TABLE Event_details( event_no INTEGER AUTOINCREMENT NOT NULL,
no_players INTEGER NOT NULL,
game_type VARCHAR(20) NOT NULL,
payout_positions INTEGER NOT NULL, 
PRIMARY KEY(event_no)
CONSTRAINT check_game_type CHECK(game_type IN ('NLH','NLO','PLO','PLH','STUD','HORSE')
CONSTRAINT check_no_players CHECK (no_players > 1)
CONSTRAINT check_payouts CHECK (payout_positions > 0 AND payout_positions < no_players));

CREATE TABLE Venue( venue_no INTEGER AUTOINCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
location VARCHAR(20) NOT NULL,
capacity INTEGER NOT NULL,
PRIMARY KEY (venue_no)
CONSTRAINT check_capacity CHECK (capacity > 0));

以及它们之间的外键:

ALTER TABLE Event_details
ADD FOREIGN KEY (venue_no)
REFERENCES Venue(venue_no)
ON DELETE SET NULL;

我想设置一个 CONSTRAINT(或 TRIGGER???),它不允许(或标记) Event_details(no_players)

这可能吗?

【问题讨论】:

  • 是的 - 感觉就像是内置在插入或更新触发器中的业务规则。只需查询适当的值并引发异常
  • 您使用的是什么版本或 Oracle?

标签: sql oracle triggers constraints


【解决方案1】:

您发布的 DDL 上的几个 cmets。

  • Oracle 中没有AUTOINCREMENT 关键字。您需要创建一个序列(通常每个表一个序列),并在 INSERT 语句本身或触发器中使用该序列中的 NEXTVAL 来填充合成主键。
  • EVENT_DETAILS 中没有创建VENUE_NO 列。我假设您的实际 DDL 正在定义该列。

您无法通过简单的CHECK 约束来强制执行此操作。您可以创建触发器

CREATE OR REPLACE TRIGGER validate_capacity
  BEFORE INSERT OR UPDATE ON event_details
  FOR EACH ROW
DECLARE
  l_venue_capacity venue.capacity%type;
BEGIN
  SELECT capacity
    INTO l_venue_capacity
    FROM venue
   WHERE venue_no = :new.venue_no;

  IF( l_venue_capacity < :new.no_players )
  THEN
    RAISE_APPLICATION_ERROR( -20001, 'Sorry, the venue has insufficient capacity' );
  END IF;
END;

但请注意,

  • 您还需要在VENUE 表上设置一个触发器,以检查对场地容量的更改是否会导致某些事件无效。通常,这需要在活动详细信息表中提供某种日期,因为据推测,场地的容量可能会随时间而变化,而您真的只希望验证以检查该场地未来的活动。
  • 基于触发器的解决方案并不总是适用于多用户环境。想象场地 1 的容量为 30。现在,会话 A 将该容量更新为 15。但在会话 A 提交之前,会话 B 插入一个事件,其 NO_PLAYERS 为 20。两个会话的触发器都不会出现问题,因此两个更改都将是允许。但是,一旦两场比赛都提交了,将在一个仅支持 15 名球员的场地中预订一个有 20 名球员的赛事。 EVENT_DETAILS 上的触发器可能会锁定 VENUE 表中的行以避免这种竞争条件,但是您正在序列化 EVENT_DETAILS 表上的插入和更新,这可能是一个性能问题,特别是如果您的应用程序曾经等待提交交易前的人工输入。

作为触发器的替代方法,您可以创建一个ON COMMIT 物化视图,将两个表连接在一起,并对该物化视图施加CHECK 约束,强制要求玩家数量不能超过场地容量。这将在多用户环境中工作,但它需要两个基表上的物化视图日志,并且它将检查移动到会话提交的点,这可能有点棘手。大多数应用程序不会考虑COMMIT 语句可能失败的可能性,因此处理这些异常可能会很棘手。从用户界面的角度来看,向用户解释问题所在可能有些棘手,因为异常可能与事务中更早进行的更改有关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-19
    • 2010-09-22
    • 2011-04-07
    • 2023-02-03
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多