所以我试图这样做,但似乎最后一行(支票)不允许其中的子查询.任何方式使这项工作Oracle?
CREATE TABLE Tank ( n_id int,day date,level int,CONSTRAINT pk_w_td PRIMARY KEY (n_id,day),CONSTRAINT fk_w_td_tan FOREIGN KEY (n_id) REFERENCES Tanks ON DELETE CASCADE,CHECK (level > 0 AND level <= (SELECT capacity FROM Tanks WHERE Tanks.n_id = TanksDay.n_id)) );
这是错误信息:
Error at Command Line:7 Column:32 Error report: sql Error: ORA-02251: subquery not allowed here 02251. 00000 - "subquery not allowed here" *Cause: Subquery is not allowed here in the statement. *Action: Remove the subquery from the statement.
解决方法
有三种基本的方法来解决这种问题,因为CHECK约束不能基于查询.
选项1:触发器
最简单的方法是在TANK上触发一个查询TANKS的触发器,如果LEVEL超过CAPACITY,则会引发异常.但是,这种简单化方法的问题在于,正确处理并发问题几乎是不可能的.如果会话1减少CAPACITY,则会话2增加LEVEL,然后两个事务提交,触发器将无法检测到违规.如果一个或两个表很少被修改,这可能不是一个问题,但一般来说这将是一个问题.
选项2:物化视图
您可以通过创建连接TANK和TANKS表的ON COMMIT实例化视图来解决并发问题,然后在实例化视图上创建一个验证LEVEL< = CAPACITY的CHECK约束.您也可以通过使物化视图仅包含违反约束的数据来避免存储数据两次.这将需要在两个基本表上的物化视图日志,这将添加一些插入开销(尽管少于使用触发器).将检查推送到提交时间将解决并发问题,但它引入了一个异常管理问题,因为COMMIT操作现在可以失败,因为实例化视图刷新失败.您的应用程序将需要能够处理该问题并提醒用户该事实. 选项3:更改数据模型 如果表A中的值取决于表B的限制,则可能表示B中的限制应该是表A的属性(而不是表B的属性).当然,这取决于您的数据模型的具体细节,但这通常值得考虑.