在数据库表级别而不是函数上进行约束
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
如果您不想使用存储过程,您的另一个选择可能是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 <..> violated
。
【讨论】:
我遇到了变异错误的问题,我尝试了您的解决方案。变异问题已解决,但触发器未触发且未引发应用程序错误。这可能是什么原因?问候 您必须插入不在基表中的视图中 哦,是的,你又来了。谢谢 还有一件事,对于像应用业务规则这样的事情,您是否推荐存储过程/函数或触发器或约束?问候 @Polppan 您不能在基表上使用check
约束来强制执行那种规则,仅仅是因为它们是单表、单行约束并且无法处理。但是您可以将它们与物化视图结合使用。我已经更新了我的答案。以上是关于在数据库表级别而不是函数上进行约束的主要内容,如果未能解决你的问题,请参考以下文章
基础入门_Python-模块和包.深入SQLAlchemy之列级别约束与表级别约束?