SQL中的检查约束中子查询

62

我能否在检查约束中使用SQL子查询?

我有一个带有列id, ownerpost
我还有另一个带有列user_id,post_id的表action
user具有列id

post_id -> post.iduser_id -> user.id 还有 post.owner -> user.id

现在我想在action表上强制执行post(post_id).id != user_id

如何做到这一点?


为什么一个引用了一个表格的列恰好有另一个表格中存在的会成为问题?你试图解决什么问题? - SingleNegationElimination
所以,如果我理解正确的话,例如动作upvote,你基本上想要防止用户给自己的 帖子 点赞? - wildplasser
2个回答

98

在CHECK约束中,不能查看当前行以外的内容。

http://www.postgresql.org/docs/9.1/interactive/sql-createtable.html指出:

作为列约束指定的CHECK约束应该只引用该列的值,而出现在表约束中的表达式可以引用多个列。

目前,CHECK表达式不能包含子查询,也不能引用除当前行的列之外的变量。

这种限制有很好的理由。但如果你喜欢在繁忙的交通中骑着独轮车玩火把,你可以使用函数来规避这个限制。然而,这种情况不会给你带来好处;相比之下,在触发器代码中执行不变性检查更加安全可靠。

http://www.postgresql.org/docs/9.1/interactive/triggers.html


6
根据Tom Lane的评论,绕过子查询限制进行编程不是一个好主意: "CHECK约束旨在处理一个行值的限制条件,独立地进行约束。如果您试图使用它来强制执行跨行条件,则项目肯定会以失败告终。" - Shane
3
是的,这是真的:“CHECK用于独立处理行值的限制条件。”但是,什么是唯一性约束?它是“在繁忙交通中骑着单轮车同时玩弄火把”吗?顺便说一句,我已经尝试过同时玩弄火把和骑单轮车。到目前为止,我还不能同时完成两件事,但也许未来可以。 - guettli
4
“在**CHECK**约束中,不支持查看当前行以外的内容。”显然,其他类型的约束(例如 UNIQUEPRIMARY KEYFOREIGN KEYEXCLUDE)必须查看超出单个行的内容。 - kgrittn
1
非常有用!出于好奇,为什么会以糟糕的方式结束? - Abraham P
10
CHECK约束中跨行引用失败的原因在于该约束只对修改的行进行评估。 因此,尽管它通常会“起初”起作用,但当其他被引用的行以一种使约束无效的方式进行修改时,这将不会被注意到。 - kgrittn

0
更好的方法是使用一个在插入/更新之前触发器来进行检查,如果检查失败,则应该引发异常,这将回滚整个插入/更新...如果检查通过,则执行插入/更新。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接