1

私は2つのテーブルを持っています:foosbars、そしてそれらの間には多対1の関係があります:それぞれfooが多くを持つことができますbarsfoobarsこれらの2つのテーブルを結合するビューもあります(そのクエリはのようなものですselect foo.*, bar.id from foos, bars where bar.foo_id=foo.id)。

foo編集: sとsの間に多対多の関係があると言ったとしても、間違いではありませんbar。ただし、 Abarは単なるタグであり(実際にはサイズです)、その名前だけで構成されています。このテーブルbarsには、リンクテーブルと同じ役割があります。

foobars「foo」の部分がfoos新しい行として挿入され、コンマで区切られた2つのbar-idで構成される「bar」の部分が分割され、そのような部分ごとにリンクが挿入されるように挿入するルールがあります。それと適切なものの間にfoo作成されます(私はそれを行うための手順を使用します)。

これはインサートに最適です。しかし、全体を更新することになると、私には問題があります。ルールのfoo一部は簡単です。barしかし、複数の部分の扱い方がわかりません。ルールのようなことをしようとするとDELETE FROM bars WHERE foo_id=new.foo_id、テーブルからすべてを削除しなくなりますbars

私は何が間違っているのですか?必要なことを達成する方法はありますか?最後に、全体に対する私のアプローチは賢明ですか?

(取得するデータは「<code> fooとそのすべて」の形式であるため、ビューを使用してこの非常に複雑なことを行いますbarが、ユーザーは表示する必要がありますfoobars。)

4

4 に答える 4

2

Rysiek、私が正しく理解していれば、foosテーブルを指す外部キーを抽出するために解析されるテキスト列がテーブルにありbarsます。リレーションを構築するこのアプローチは、場合によっては正当化されるかもしれませんが、データベース プログラミングのほとんどすべてのガイド/チュートリアルでは、そうすることを思いとどまらせるでしょう。barsfoo in を指す標準の外部キー in を使用しないのはなぜfoosですか? バーを複数の foo に割り当てる必要がある場合を除きます。もしそうなら、これはあなたの関係を一対多ではなく多対多として識別します。どちらの状況でも、標準の外部キー ベースのソリューションを使用する方が、データベースにとってより自然に思えます。

1 対多の関係の db スキーマの例:

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
);

また、テーブルの乗算 (SELECT FROM foos、bars) の代わりに INNER JOIN を使用することをお勧めします。

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

削除のコンテキストでは new.foo_id が正しいとは思いません。

DELETE FROM bar WHERE 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 に答える
0

これが私が実際に対処した方法です。一意の制約違反が発生した場合、更新する代わりに、単に を削除しfoo、カスケードに を処理させbarsます。次に、もう一度挿入しようとします。それを行うには複数の SQL ステートメントを使用する必要がありますが、うまくいくようです。

于 2008-10-02T19:57:12.860 に答える