使用 SQL 定义一对多关系

发布于 2024-12-20 12:03:01 字数 811 浏览 1 评论 0原文

我正在寻找一种在两个表之间建立一对多关系的方法。下面解释了表结构,但我试图忽略与问题无关的所有内容。

objects 有 1 列,称为 uuid

contents 有 3 列,分别称为 contentobject_uuidtimestamp

基本思想是向 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 in objects (a foreign key should do)
  • No row in objects exists without at least a row in contents

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冷心人i 2024-12-27 12:03:01

您的主要问题是除了外键约束之外;没有约束可以引用另一个表。

最好的选择是对其进行稍微非规范化,并在 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 of contents 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.

几度春秋 2024-12-27 12:03:01

也许你想做的就是更加正常化一点。您需要第三个表,它引用其他表的元素。表对象应该有自己的uuid,表内容也应该有自己的uuid,并且不引用表对象。第三个表应该只包含对其他两个表的引用,但主键是两个引用的组合。
例如,您有一个表 objects 的 uuid,并且您想要该 uuid 的所有内容,假设第三个表具有列 object_uuid 和 content_uuid,并且表内容有自己的串行列,名为uuid,您的查询应该是这样的:

SELECT * FROM thirdtable,contents 
   WHERE thirdtable.content_uuid = contents.uuid AND thirdtable.object_uuid=34;

然后您可以在每个表上使用插入触发器

CREATE TRIGGER my_insert_trigger AFTER INSERT OR UPDATE ON contents
   FOR EACH ROW EXECUTE PROCEDURE my_check_function();

,然后在函数 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 table contents sholud have also its own uuid and no reference to the table objects. 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:

SELECT * FROM thirdtable,contents 
   WHERE thirdtable.content_uuid = contents.uuid AND thirdtable.object_uuid=34;

Then you can use an on insert trigger on every table

CREATE TRIGGER my_insert_trigger AFTER INSERT OR UPDATE ON contents
   FOR EACH ROW EXECUTE PROCEDURE my_check_function();

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文