在数据库内强制执行表间约束的最佳方法
我正在寻找检查表间约束的最佳方法,比外键向前迈出了一步。 例如,检查日期子记录值是否位于两个父行列上的范围日期之间。 例如:
Parent table
ID DATE_MIN DATE_MAX
----- ---------- ----------
1 01/01/2009 01/03/2009
...
Child table
PARENT_ID DATE
---------- ----------
1 01/02/2009
1 01/12/2009 <--- HAVE TO FAIL!
...
我看到两种方法:
- 在提交时创建物化视图,如本文< /a> (或其他 RDBMS 上的其他等效项)。
- 使用存储过程和触发器。
还有其他方法吗? 哪个是最好的选择?
更新:这个问题的动机不是关于“对数据库或应用程序施加约束”。 我认为这是一个令人厌倦的问题,每个人都按照自己喜欢的方式去做。 而且,我对批评者感到抱歉,我正在开发时受到数据库的限制。 从这里,问题是“管理数据库表间约束的最佳选择是什么?”。 我在问题标题上添加了“数据库内部”。
更新2:有人添加了“oracle”标签。 当然,物化视图是 Oracle 工具,但我对任何选项感兴趣,无论它是在 Oracle 还是其他 RDBMS 上。
I looking for the best way to check for inter-table constraints an step forward of foreing keys. For instance, to check if a date child record value is between a range date on two parent rows columns. For instance:
Parent table
ID DATE_MIN DATE_MAX
----- ---------- ----------
1 01/01/2009 01/03/2009
...
Child table
PARENT_ID DATE
---------- ----------
1 01/02/2009
1 01/12/2009 <--- HAVE TO FAIL!
...
I see two approaches:
- Create materialized views on-commit as shown in this article (or other equivalent on other RDBMS).
- Use stored-procedures and triggers.
Any other approach? Which is the best option?
UPDATE: The motivation of this question is not about "putting the constraints on database or on application". I think this is a tired question and anyone does the way she loves. And, I'm sorry for detractors, I'm developing with constraints on database. From here, the question is "which is the best option to manage inter-table constraints on database?". I'm added "inside database" on the question title.
UPDATE 2: Some one added the "oracle" tag. Of course materialized views are oracle-tools but I'm interested on any option regardless it's on oracle or others RDBMSs.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
编辑:Dana the Sane 删除了他的帖子,该帖子本来是不顾 DBA 的反对将其放入数据层的。
DBA 对像 Dana 这样的开发人员大喊大叫的原因是他们认为应用程序和数据库之间的比例是 1:1。 他们看到这一点是因为他们看到数据是为了支持应用程序而他们的应用程序只需要将数据存储在一个地方。
DBA 将数据视为最重要的事情,并不关心应用程序的出现或消失。
如果您不再使用 MS Word,您会关心是否仍然可以访问您的文档吗? 不,数据对您来说很重要,应用程序则不重要。
如果您让任何东西绕过您的应用程序来获取您的数据,那么您就失去了数据层中的约束。 如果您的约束在数据库层,那么几十个应用程序都可以使用它。
理想情况下,您永远不会向任何人授予 INSERT、UPDATE 或 DELETE 权限。 相反,您将授予 EXECUTE On 将为您执行 CRUD 的包。 如果您从一开始就这样做,那么向 CHILD 的 INSERT 添加规则的能力(例如检查出生日期是否在父母日期之间)实际上是无限的。
EDIT: Dana the Sane deleted his post which was to put it in the data layer regardless of DBA objections.
The reasons DBAs scream at Developers like Dana is they assume that there's a 1:1 ratio between applications and databases. They see this because they see the data as there to support the app and their app only needs to store data in one place.
DBA's see the data as the most important thing, and don't care if the app comes or goes.
If you lost the use of MS Word, would you care if you could still get to your documents? No, the data is important to you, the app isn't.
If you ever let anything bypass your app, to get to your data, you've lost your constraints in your data layer. If your constraints are in your database layer, a dozens apps would all be able you use it.
Ideally, you'd never grant INSERT, UPDATE or DELETE to anyone. Instead you'd grant EXECUTE On packages that will do the CRUD for you. If you do this from the beginning, the ability to add rules to the INSERT of a CHILD (like checking if birth is between parent dates) is virtually infinite.
数据库约束
实施数据库约束的最佳方式(跨越两个或多个关系的约束 - 其中引用完整性约束是具有句法简写的特殊情况,<代码>外键/
引用
语句)将是声明式,通过标准SQL语句:在您的情况下,某些东西就像:
更新:我忘记
严格来说是一个布尔值,因此旧代码不正确。不幸的是(这里有适度的讽刺)大多数 SQL-DBMS 不实现 ASSERTION。
因此,需要使用存储过程和触发器或检查约束(如果可用)按程序实现此检查。 在这种情况下,需要调用相同的存储过程来更新父级和子级关系; 所以一个过程和两个触发器或检查约束。
Lurker Indeed 的回答展示了这样的解决方案,但它需要对子关系进行类似的检查。
对性能的担忧
Damien_The_Unknowner,在评论 同样的答案,认为:
在这里,我将解决这个反对意见,因为它很常见,甚至对于 ASSERTION 来说似乎也有效(这很可能是一个流行的误解,说服用户不要向 SQL-DBMS 实现者询问它们,即使当他们知道它在标准中时)。
嗯,是的,他是对的……如果一个人使用 DBMS,那就太糟糕了!
有一个有趣的理论可以应用于完整性维护: 微分关系微积分(以 .pdf 形式提供 在这里;您还可以在每本有关 DB 理论的不错的书中找到对该主题的充分处理。
核心思想是可以强制执行完整性约束,通常只检查更新涉及的关系子集。 更严格地说,引用链接论文的摘要:
还有其他技术可以处理增量完整性约束维护。 DBMS 开发人员没有充分的理由忽视这一理论。 事实上,业余爱好者对 SQL 中完整性约束和完整性检查的介绍 ( .pdf)在简介中写道:
所以,请:要求您的 SQL-DBMS 供应商(商业或免费/开源)立即实施 ASSERTION,并且至少具有合理的性能。
Database constraints
The best way to enforce a database constraint (a constraint which span two or more relations - of which a referential integrity constraint is a particular case with a syntactical shorthand,
foreign key
/references
statements) would be declaratively, by means of the standard SQL statement:In your case, something like:
UPDATE: I forgot that
<condition>
is strictly a boolean, therefore the old code was not correct.Unfortunately (moderate sarcasm here) most SQL-DBMSes do not implement ASSERTIONs.
So one is left to implement this check procedurally, with stored procedures and triggers or check constraints, if available. In this case one needs to call the same stored procedures for updates to both Parent and Child relations; so one procedure and two triggers or check constraints.
Lurker Indeed's answer shows such solution, but it needs a similar check on Child relation.
Concerns about performances
Damien_The_Unbeliever, in a comment to the same answer, argues:
Here I will address this objection, because it is very common and may seem valid even for ASSERTIONs (it is likely that this is a popular misconception that persuades users to not ask SQL-DBMS implementors about them, even when they know that it is in the standard).
Well, yes, he is right.. if one uses a DBMS that sucks!
There is an interesting piece of theory that it is possible to apply to integrity maintenance: Differential Relational Calculus (available as .pdf here; you also find adequate treatment of the subject in every decent book about DB theory).
The core idea is that it is possible to enforce integrity constraints often checking only subsets of relations involved by an update. More rigorously, quoting abstract of the linked paper:
There are other techniques to deal with incremental integrity constraints maintenance. There are no good reasons for DBMS developers to ignore such theory. In fact, the authors of An Amateur's Introduction to Integrity Constraints and Integrity Checking in SQL (.pdf) wrote in the introduction:
So, please: ask your SQL-DBMS supplier (commercial or free/open source) to implement ASSERTIONs now and with, at least, reasonable performance.
我会选择存储过程和触发器路线; 它们的主要目的之一是确保数据库级别的数据完整性。
大多数数据库还具有某种形式的检查约束,其中几乎任何可以放入 WHERE 子句的内容都可以用作对数据的检查:
I'd go the stored proc and trigger route; one of their major purposes is to ensure data integrity at the DB level.
Most databases also have some form of check constraints, in which pretty much anything you can put in a WHERE clause can be used as a check against the data:
好吧,在具体的例子中,我会冗余地存储冗余数据。 通过 CHECK 和 FK(以及超级键)的组合,我们确保数据始终正确,然后我们围绕它包装一个视图和触发器以隐藏实现细节:
这是针对 SQL Server 的。 在 2005 年进行了测试,但至少也应该适用于 2000 年和 2008 年。 这里的一个好处是,即使触发器被禁用(例如嵌套触发器被关闭),您也不会在基表中得到错误数据
Okay, in the specific example, I'd go for redundantly storing redundant data. Through a combination of CHECKs and FKs (and super keys), we ensure that the data is always correct, then we wrap a view and triggers around this to hide the implementation details:
This is for SQL Server. Tested on 2005, but should work on at least 2000 and 2008 too. A bonus here is that even if the trigger is disabled (e.g. nested triggers are turned off), You cannot end up with wrong data in the base tables