【问题标题】: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. 最好有约束或触发器来实现业务规则?问候
  • 触发器是执行此操作的方法 - 但请先阅读stackoverflow.com/questions/460316/are-database-triggers-evil。根据我的经验,触发器往往需要非常高的回报来支付额外的复杂性。如果您对此有实际问题,请考虑一下,但如果它是“以防万一”,我可能不会创建触发器....

标签: database oracle plsql oracle10g constraints


【解决方案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
    

    如果您不想使用存储过程,您的另一个选择可能是view 和instead 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 约束来强制执行那种规则,仅仅是因为它们是单表、单行约束并且无法处理。但是您可以将它们与物化视图结合使用。我已经更新了我的答案。
    猜你喜欢
    • 2011-02-05
    • 2010-10-02
    • 1970-01-01
    • 2011-02-07
    • 2021-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多