在数据库表级别而不是函数上进行约束

Posted

技术标签:

【中文标题】在数据库表级别而不是函数上进行约束【英文标题】:Constraint at database table level instead of function 【发布时间】:2012-09-24 08:30:46 【问题描述】:

我有以下选择语句,我在一个函数中使用它来检查记录的重叠,这个函数是从应用程序前端调用的。

SELECT count(*),product_no 
from products p where lower(p.PRODUCT_REG_NO) ='GB-UNIGAS' 
and (NVL (p.return_date, p.end_date) >= '01-Jan-2015') 
and p.product_no in (select product_no from PRODUCT_MASTER  where  EXPIRED='N' 
                    and product_no  = p.product_no)

我想在表中创建一个约束,而不是检查记录重叠的函数,这样即使在数据库级别也不会有任何插入或更新。

如何用上面的sql语句创建一个约束?

任何帮助都是非常值得赞赏的。

谢谢

【问题讨论】:

使用 BEFORE INSERT OR UPDATE 触发器docs.oracle.com/cd/B10500_01/appdev.920/a96590/adg13trg.htm(往下看 3/4,在“复杂检查约束的触发器:示例”处) 与您的问题没有直接关系,但我强烈建议使用具有已定义日期格式的 to_date() 而不是 NVL (p.return_date, p.end_date) >= '01-Jan -2015')。否则,您的应用程序将无法在其他语言环境中正常运行。 @lc. 最好有约束或触发器来实现业务规则?问候 触发器是执行此操作的方法 - 但请先阅读***.com/questions/460316/are-database-triggers-evil。根据我的经验,触发器往往需要非常高的回报来支付额外的复杂性。如果您对此有实际问题,请考虑一下,但如果它是“以防万一”,我可能不会创建触发器.... 【参考方案1】:

您可以创建一个插入前或更新触发器,检查您的条件,并在新数据不符合您的要求时引发错误。这个link 会帮助你。

【讨论】:

【参考方案2】:

在存储过程中保留这种逻辑是一个不错的选择。尝试在触发器中实现该逻辑,您最终会以某种方式查看

ORA-04091: table <your table> is mutating, trigger/function may not see it

例如,在触发器中实现该功能将允许您使用 insert like

insert into <Yourtable> (<col1>...<coln>)
   values(val1... valn)

但是如果你尝试像这样执行insert,你肯定会得到mutating table错误

 insert into <Yourtable> (<col1>...<coln>)
    select col1, .. coln 
      from some_table

如果您不想使用存储过程,您的另一个选择可能是viewinstead of trigger

Create or replace view <ViewName> as
  select *
    from your_table;

 create or replace trigger <Trigger_name> 
   instead of insert on <View_Name>
 begin
   -- your logic
 end;

另外

还可以通过约束(CHECK 约束)强制执行业务规则,您可以将 CHECK 约束和 materialized view 组合如下: 为您的表创建物化视图(不要忘记在之前创建materialized view log),以查询违反业务规则约束的数据。

 Create materialized view MV_1
  refresh complete on commit as
  --here goes your query
  -- selecting data you want to raise exception on

添加始终为 false 的 check 约束。像这样的

alter table MV_1 add constraint CHK check(1=2) deferrable;

完成此操作后,当您尝试在表中插入违反业务规则约束的数据时,您将收到 check constraint &lt;..&gt; violated

【讨论】:

我遇到了变异错误的问题,我尝试了您的解决方案。变异问题已解决,但触发器未触发且未引发应用程序错误。这可能是什么原因?问候 您必须插入不在基表中的视图中 哦,是的,你又来了。谢谢 还有一件事,对于像应用业务规则这样的事情,您是否推荐存储过程/函数或触发器或约束?问候 @Polppan 您不能在基表上使用check 约束来强制执行那种规则,仅仅是因为它们是单表、单行约束并且无法处理。但是您可以将它们与物化视图结合使用。我已经更新了我的答案。

以上是关于在数据库表级别而不是函数上进行约束的主要内容,如果未能解决你的问题,请参考以下文章

基础入门_Python-模块和包.深入SQLAlchemy之列级别约束与表级别约束?

分区表与分区索引

使用表值函数以列而不是行返回数据

数据库触发器对于跨表完整性约束是不是安全?

oracle 数据库 - 插入具有唯一键约束的表显示当值实际重复时插入 1 行。 - 发生在函数中

SQL 表变量 - 添加检查匹配行集是不是存在的约束