1

我有两个表:foosand bars,并且它们之间存在多对一的关系:每个表foo可以有很多bars. 我还有一个 view foobars,它连接了这两个表(它的查询就像select foo.*, bar.id from foos, bars where bar.foo_id=foo.id)。

foo编辑:如果您说s 和s之间存在多对多关系,那您就不会错bar。然而, Abar只是一个标签(实际上,它是一个大小),并且只包含它的名称。该表bars具有与链接表相同的作用。

我有一个关于插入的规则,foobars即“foo”部分foos作为新行插入,“bar”部分由几个用逗号分隔的 bar-id 组成,每个这样的部分都有一个链接在它和适当的之间foo创建(我使用一个过程来做到这一点)。

这对插入非常有用。但是,在更新整个事物时,我遇到了问题。规则的foo部分很简单。但是,我不知道如何处理多个bars 部分。当我尝试DELETE FROM bars WHERE foo_id=new.foo_id在规则中执行类似操作时,我会从 table 中删除所有内容bars

我究竟做错了什么?有没有办法实现我所需要的?最后,我对整个事情的处理方式是否明智?

(我对视图做了这个过于复杂的事情,因为我得到的数据是“<code>foo and all its bars”的形式,但用户必须只看到foobars。)

4

4 回答 4

2

Rysiek,如果我理解正确,您在foos表中有文本列,该列被解析以提取指向bars表的外键。在某些情况下,这种建立关系的方法可能是合理的,但是几乎所有数据库编程指南/教程都不鼓励这样做。为什么不使用bars指向 foo in 的标准外键foos呢?除非需要将 bar 分配给多个 foo。如果是这样,这将您的关系标识为多对多而不是一对多。在这两种情况下,使用基于标准外键的解决方案对于数据库来说似乎更自然。

一对多关系的示例数据库模式:

CREATE TABLE foos (
    id SERIAL PRIMARY KEY,
    ....
);
CREATE TABLE bars (
    id SERIAL PRIMARY KEY,
    foo_id INT REFERENCES bars (id) ON DELETE CASCADE,
    ...
);

对于多对多关系也是如此:

CREATE TABLE foos (
    id SERIAL PRIMARY KEY,
    ....
);
CREATE TABLE bars (
    id SERIAL PRIMARY KEY,
    ...
);
CREATE TABLE foostobars (
    foo_id INT REFERENCES foos (id) ON DELETE CASCADE,
    bar_id INT REFERENCES bars (id) ON DELETE CASCADE
);

我还建议使用 INNER JOIN 而不是表乘法(SELECT FROM foos,bars)。

CREATE VIEW foobars AS
SELECT
    foos.id AS foo_id, foos.something,
    bars.id AS bar_id, bars.somethingelse
FROM foos
INNER JOIN bars ON bars.foo_id = foo.id;

多对多 INNER JOINS 相同

CREATE VIEW foobars AS
SELECT
    foos.id AS foo_id, foos.something,
    bars.id AS bar_id, bars.somethingelse
FROM foos
INNER JOIN foostobars AS ftb ON ftb.foo_id = foo.id
INNER JOIN bars ON bars.id = ftb.bar_id;
于 2008-10-02T02:25:48.817 回答
0

这就是我实际处理它的方式:当我遇到唯一约束违规时,我没有更新,而是简单地删除foo并让级联处理bars. 然后我只是尝试再次插入。我必须使用多个 SQL 语句才能做到这一点,但它似乎有效。

于 2008-10-02T19:57:12.860 回答
0

我认为 new.foo_id 在删除的上下文中是不正确的。

不应该是从酒吧中删除 foo_id=old.foo_id 吗?

于 2008-10-02T02:17:17.010 回答
0

删除问题是您正在删除的谓词不是基于您要从中删除的表。您需要根据连接谓词进行删除。这看起来有点像:

delete b
  from foo f
  join foobar fb
    on f.FooID = fb.FooID
  join bar b
    on b.BarId = fb.BarID
 where f.FooID = 123

这让您可以创建一个 Foo 表、一个 Bar 表和一个记录 Foo 所具有的 Bar 的连接表。您无需编写列表并将它们分开。这是一件坏事,因为查询优化器不能使用索引来识别相关记录——实际上这违反了 1NF 的“无重复组”规则。正确的架构看起来像:

Create table Foo (
     FooID int
    ,[Other Foo attributes]
)

Create table Bar (
     BarID int
    ,[Other Bar attributes]
)

Create table FooBar (
     FooID int
    ,BarID int
)

通过适当的索引,M:M 关系可以存储在 FooBar 中,并且 DBMS 可以在其本机数据结构中有效地存储和操作它。

于 2008-10-03T22:53:37.993 回答