简体   繁体   English

Oracle SQL检查约束

[英]Oracle Sql Check Constraint

What I want to do is simple and below are details. 我想做的很简单,下面是详细信息。 I have two tables. 我有两张桌子。

Create Table Event(
IDEvent number (8) primary key,
StartDate date not null,
EndDate date not null
);

This is fine. 这可以。

Here is second table. 这是第二张桌子。

Create Table Game(
IDGame number (8) primary key,
GameDate date not null,
constraint checkDate 
check (GameDate >= to_date(StartDate references from Event(StartDate)))
);

The constraint checkDate is to check if the date is bigger than the startdate. 约束checkDate用于检查日期是否大于开始日期。 While checking I'm getting error : Missing right parenthesis . 在检查时出现错误: Missing right parenthesis

My question is, If this is possible to do then why it is giving me an error? 我的问题是,如果可以这样做,那为什么会给我一个错误?

A check constraint in a table can only verify conditions on the columns of that particular table. 表中的检查约束只能验证该特定表的列上的条件。 You can not refer to columns from other tables. 您不能引用其他表中的列。

If you need to verify conditions that involves columns from a different table, you can do it from a before insert/update trigger on that table. 如果需要验证涉及不同表中列的条件,则可以从该表上的插入/更新之前触发器执行此操作。

What you want to do is far from simple. 您要做的绝非简单。

The syntax you propose, doesn't work on any RDBMS. 您建议的语法不适用于任何RDBMS。 It would be nice to have, but none of the RDBMS vendors have implemented it, because it enforcing such a cross table integrity rule would mean locking the referenced table while updating the game table. 拥有它会很好,但是没有一个RDBMS供应商实现它,因为它强制执行这种跨表完整性规则将意味着在更新游戏表时锁定引用表。 If you try to build it yourself, you'll have to do the locking yourself. 如果尝试自己构建,则必须自己锁定。 You'll have to take into account all actions that could possibly violate your rule, such as: 您必须考虑所有可能违反您的规则的操作,例如:

  • inserting a game 插入游戏
  • updating the gamedate to a less recent date 将游戏日期更新为较新的日期
  • updating the event startdate to a more recent date 将事件开始日期更新为最近的日期
  • deleting an event 删除活动

And for each of these actions you'll have to think of writing code that is multi user proof, by locking the right records in the other table. 对于每个操作,您都必须考虑通过将正确的记录锁定在另一个表中来编写多用户证明的代码。

If you want to reduce this complexity, you might want to look at a product called RuleGen (www.rulegen.com) 如果要减少这种复杂性,则可能需要查看一种名为RuleGen(www.rulegen.com)的产品。

Or you may want to build a specific API and include the checks in just the right places. 或者,您可能希望构建特定的API,并在正确的位置包含检查。 You'll still have to manually lock yourself in this scenario. 在这种情况下,您仍然必须手动锁定自己。

Hope this helps. 希望这可以帮助。

Regards, 问候,
Rob. 抢。

There is one hack that you can make, but I doubt that performance of inserting games or events will be acceptable, once the tables grow to a certain size: 您可以使用一种技巧,但是我怀疑一旦表增长到一定大小,插入游戏或事件的性能是否可以接受:

CREATE TABLE Event 
(
  IDEvent     NUMBER(8) PRIMARY KEY,
  StartDate   DATE NOT NULL,
  EndDate     DATE NOT NULL
);

CREATE TABLE Game 
(
  IDGame     NUMBER(8) PRIMARY KEY,
  GameDate   DATE NOT NULL,
  eventid    NUMBER(8),   -- this is different to your table definition
  CONSTRAINT fk_game_event FOREIGN KEY (eventid) REFERENCES event (idevent)
);

CREATE INDEX game_eventid ON game (eventid);

CREATE MATERIALIZED VIEW LOG ON event 
   WITH ROWID, SEQUENCE (idevent, startdate) INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW LOG ON game 
   WITH ROWID, SEQUENCE (idgame, eventid, gamedate) INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW mv_event_game
REFRESH FAST ON COMMIT WITH ROWID
AS
SELECT ev.idevent, 
       ev.startdate, 
       g.gamedate
FROM event ev, game g
WHERE g.eventid = ev.idevent;  

ALTER TABLE mv_event_game 
  ADD CONSTRAINT check_game_start check (gamedate >= startdate);

Now any transaction that inserts a game that starts before the referenced event will throw an error when trying to commit the transaction: 现在,任何插入要在引用事件之前开始的游戏的事务都将在尝试提交事务时引发错误:

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning and OLAP options

SQL> INSERT INTO event
  2  (idevent, startdate, enddate)
  3  values
  4  (1, date '2012-01-22', date '2012-01-24');

1 row created.

SQL>
SQL> INSERT INTO game
  2  (idgame, eventid, gamedate)
  3  VALUES
  4  (1, 1, date '2012-01-01');

1 row created.

SQL> commit;
commit
*
ERROR at line 1:
ORA-12008: error in materialized view refresh path
ORA-02290: check constraint (FOOBAR.CHECK_GAME_START) violated

But again: This will make inserts in both tables slower as the query inside the mview needs to be run each time a commit is performed. 但同样:内MVIEW需要每次执行承诺中运行这将使这两个表中插入作为查询慢。

I wasn't able to change the refresh type to FAST which probably would improve commit performance. 我无法将刷新类型更改为FAST ,这可能会提高提交性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM