使用 SQL 定义一对多关系
我正在寻找一种在两个表之间建立一对多关系的方法。下面解释了表结构,但我试图忽略与问题无关的所有内容。
表 objects
有 1 列,称为 uuid
。
表 contents
有 3 列,分别称为 content
、object_uuid
和 timestamp
。
基本思想是向 objects
中插入一行并从数据库获取一个新的 uuid
。然后,使用此 uuid
存储在 contents
中的每一行,以将内容与对象关联起来。
现在我尝试使用数据库来强制执行:
contents
中的每一行都引用objects
中的一行(应该使用外键)objects 中没有行
存在,contents
中至少没有行
这些约束应在提交事务时强制执行。
普通触发器无济于事,可能是因为当写入 objects
表中的一行时,contents
中还没有一行。 Postgres 确实有所谓的约束触发器
,可以推迟到事务结束。可以使用它们,但它们似乎是某种内部构造,不适合日常使用。
想法或解决方案应该是标准 SQL(首选)或与 Postgres 一起使用(版本无关紧要)。感谢您的任何意见。
I'm looking for a way to set up a one to many relationship between 2 tables. The table structures is explained below but I've tried to leave everything off that has nothing to do with the problem.
Table objects
has 1 column called uuid
.
Table contents
has 3 columns called content
, object_uuid
and timestamp
.
The basic idea is to insert a row into objects
and get a new uuid
from the database. This uuid
is then used stored for every row in contents
to associate contents with objects.
Now I'm trying to use the database to enforce that:
- Each row in
contents
references a row inobjects
(a foreign key should do) - No row in
objects
exists without at least arow
incontents
These constraints should be enforced on commit of transactions.
Ordinary triggers can't help probably because when a row in the objects
table is written, there can't be a row in contents
yet. Postgres does have so called constraint triggers
that can be deferred until the end of the transaction. It would be possible to use those but they seem to be some sort of internal construct not intended for everyday use.
Ideas or solutions should be standard SQL (preferred) or work with Postgres (version does not matter). Thanks for any input.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的主要问题是除了外键约束之外;没有约束可以引用另一个表。
最好的选择是对其进行稍微非规范化,并在
object
上有一列,其中包含引用它的contents
的数量。您可以创建一个触发器来保持最新状态。contents_count INTEGER NOT NULL DEFAULT 0
除非您对谁可以更新此列设置一些用户安全措施,否则这不会是牢不可破的。但是,如果您通过触发器使其保持最新,并且您想要避免的只是意外损坏,那么这应该足够了。
编辑:根据评论,
CHECK
约束不可推迟。如果删除所有内容,即使目的是在同一事务中添加更多内容,此解决方案也会引发错误。Your main problem is that other than foreign key constraints; no constraint can reference another table.
Your best bet is to denormalize this a little and have a column on
object
containing the count ofcontents
that reference it. You can create a trigger to keep this up to date.contents_count INTEGER NOT NULL DEFAULT 0
This won't be as unbreakable unless you put some user security over who can update this column. But if you keep it up to date with a trigger and all you're looking to avoid is accidental corruption, this should be sufficient.
EDIT: As per the comment,
CHECK
constraints are not deferrable. This solution would raise an error if all the contents are removed even if the intention is to add more in the same transaction.也许你想做的就是更加正常化一点。您需要第三个表,它引用其他表的元素。表
对象
应该有自己的uuid,表内容
也应该有自己的uuid,并且不引用表对象
。第三个表应该只包含对其他两个表的引用,但主键是两个引用的组合。例如,您有一个表
objects
的 uuid,并且您想要该 uuid 的所有内容,假设第三个表具有列 object_uuid 和 content_uuid,并且表内容有自己的串行列,名为uuid,您的查询应该是这样的:然后您可以在每个表上使用插入触发器
,然后在函数 my_check_function() 中删除第三个表中不存在的
objects
中的每一行。我回答的时候其他人先回答了,如果你们喜欢我的解决方案,我可以帮助你们制作 my_check_function() 函数。Maybe what you want to do is normalize a little bit more. You need a third table, that references elements of the other tables. Table
objects
should have its own uuid and tablecontents
sholud have also its own uuid and no reference to the tableobjects
. The third table should have only the references to the other two tables, but the primary key is the combination of both references.so for example you have an uuid of the table
objects
and you want all the contents of that uuid, assuming that the third table has as columns object_uuid and content_uuid, and the table contents has its own serial column named uuid, your query should be like this:Then you can use an on insert trigger on every table
and then in function my_check_function() delete every row in
objects
that is not present in the third table. Somebody else answered first while I was answering, if you guys like my solution I could help you to make the my_check_function() function.