Oracle数据库强制检查多个表

时间:2010-04-11 13:53:56

标签: sql oracle

我试图在多个表的ORACLE数据库中强制执行CHECK约束

CREATE TABLE RollingStocks ( 
  Id NUMBER,
  Name Varchar2(80) NOT NULL,           
  RollingStockCategoryId NUMBER NOT NULL,            
  CONSTRAINT Pk_RollingStocks Primary Key (Id),
  CONSTRAINT Check_RollingStocks_CategoryId  
  CHECK ((RollingStockCategoryId  IN (SELECT Id FROM FreightWagonTypes)) 
        OR 
        (RollingStockCategoryId  IN (SELECT Id FROM LocomotiveClasses)))       
);

...但我收到以下错误:

  

*原因:声明中不允许使用子查询。   *操作:从语句中删除子查询。

您能帮助我了解问题是什么或如何获得相同的结果吗?

3 个答案:

答案 0 :(得分:2)

Oracle中的检查约束非常有限。要按照您的建议进行检查,您必须实施PL/SQL trigger

我的建议是完全避免触发器。实现修改数据库并包含检查的存储过程。存储过程更容易维护,但实现起来稍微困难一些。但是从长期来看,将前端从直接表访问更改为存储过程访问可以多次回报。

答案 1 :(得分:2)

您要做的是确保插入一个表中的值存在于另一个表中,即强制执行外键。那就是:

CREATE TABLE RollingStocks ( 
...

  CONSTRAINT Pk_RollingStocks Primary Key (Id),
  CONSTRAINT RollingStocks_CategoryId_FK (RollingStockCategoryId )
     REFERENCES FreightWagonTypes (ID)      
);  

除了您要强制引用两个表的外键之外。这是不可能做到的。

你有几个选择。一种方法是将FreightWagonTypes和LocomotiveClasses合并为一个表。如果您需要为应用程序的其他部分使用单独的表,则可以构建物化视图以强制执行外键。物化视图类似于表,可以通过外键引用。如果两个表的键值发生冲突,则此选项将不起作用。

另一个选择是认识到两个候选参考表的存在表明RollingStock可能需要分成两个表 - 或者可能三个:超级型和两个子型表,即RollingStock和FreightWagons,Locomotives。

那么,PassengerCoaches,GuardsWagons和RestaurantCars呢?

答案 2 :(得分:0)

不幸的是,Oracle不支持这样的复杂检查约束。

在这种情况下,您最好的选择是稍微更改数据模型 - 在FreightWagonTypesLocomotiveClasses上添加父表,这将保留这两个表中的所有ID。这样,您就可以将FK添加到单个表中。