2012-04-09 42 views
13

私は2つのテーブルの書籍とオーディオブックを持っています。どちらもISBNを主キーとしています。書籍とオーディオブックISBNに外部キー制約があるisbn属性を持つテーブルwrittenbyがあります。私がwrittenbyに挿入するときに起こる問題は、postgresqlがbooksbyとAudiobooksの両方にあるためにwrittenbyに挿入するISBNを望んでいることです。作者と書いた本/オーディオブックを格納するテーブルを書きましたが、これはpostgresqlのテーブルには変換されません。私が実装しようとしている代替ソリューションは、audiobook_writtenbyとbooks_writtenbyの2つの新しい関係があったが、それが良い選択肢であるかどうかはわからない。 1つのテーブルを2つの異なるテーブルを参照して書き込むという私の元のアイデアをどのように実装するのか、あるいはデータベースをよりうまく設計する方法を私に教えてください。より多くの情報が必要な場合はお知らせください。POSTGRESQL外部キー2つの異なるテーブルの主キーを参照する

答えて

4

RDBMSは、多型外部キー制約をサポートしていません。あなたがやりたいことは合理的ですが、リレーショナルモデルとORMシステムを作るときのオブジェクトリレーショナルインピーダンスミスマッチの本当の問題の1つに十分に適応したものではありません。 Nice discussion on this on Ward's WIki

テーブルにknown_isbnsという別のテーブルを作成し、BooksおよびAudioBooksで制約および/またはトリガーを設定して、両方のタイプのブックテーブルのすべての有効なisbnsがテーブルに含まれるようにすることが考えられます。そして、writtenbyのあなたのFK制約はknown_isbnsに対してチェックします。

+3

リレーショナルモデルとSQLデータベースは実際にこの種の問題をうまく処理します。問題はリレーショナルまたはSQLではありません。問題は明らかな制約の1つが正しく実装されていないことです。 (制約は、書籍とオーディオブックのISBNが同じドメインから引き出されているということです) –

3

テーブルの継承を使用して、両方の世界の中で最高のものを得ることができます。書き込まれたテーブルを参照するINHERITS句でaudiobook_writtenbyとbooks_writtenbyを作成します。外部キーは、説明しているように子レベルで定義できますが、依然として上位レベルのデータを参照できます。 (。あなたは、ビューでこれを行うことができますが、継承はこの場合にはクリーナーかもしれないように聞こえる)

のドキュメントを参照してください:

http://www.postgresql.org/docs/current/interactive/sql-createtable.html

http://www.postgresql.org/docs/current/interactive/tutorial-inheritance.html

http://www.postgresql.org/docs/current/interactive/ddl-inherit.html

これを行うと、おそらくBEFORE INSERTトリガーをwrittenbyテーブルに追加することになります。

26

PostgreSQLでこれを行う方法は複数あります。個人的には、私はこの方法が好きです。

-- This table should contain all the columns common to both 
-- audio books and printed books. 
create table books (
    isbn char(13) primary key, 
    title varchar(100) not null, 
    book_type char(1) not null default 'p' 
    check(book_type in ('a', 'p')), 
    -- This unique constraint lets the tables books_printed and books_audio 
    -- target the isbn *and* the type in a foreign key constraint. 
    -- This prevents you from having an audio book in this table 
    -- linked to a printed book in another table. 
    unique (isbn, book_type) 
); 

-- Columns unique to printed books. 
create table books_printed (
    isbn char(13) primary key references books (isbn), 
    -- Allows only one value. This plus the FK constraint below guarantee 
    -- that this row will relate to a printed book row, not an audio book 
    -- row, in the table books. The table "books_audio" is similar. 
    book_type char(1) default 'p' 
    check (book_type = 'p'), 
    foreign key (isbn, book_type) references books (isbn, book_type), 
    other_columns_for_printed_books char(1) default '?' 
); 

-- Columns unique to audio books. 
create table books_audio (
    isbn char(13) primary key references books (isbn), 
    book_type char(1) default 'a' 
    check (book_type = 'a'), 
    foreign key (isbn, book_type) references books (isbn, book_type), 
    other_columns_for_audio_books char(1) default '?' 
); 

-- Authors are common to both audio and printed books, so the isbn here 
-- references the table of books. 
create table book_authors (
    isbn char(13) not null references books (isbn), 
    author_id integer not null references authors (author_id), -- not shown 
    primary key (isbn, author_id) 
); 
-1

この特定の例では、複数のテーブルを使用する必要は全くありません。該当する場合は、テーブル「ブック」を使用して、「AudioBook」から列を追加してください。非常に特定の列で表レベルを区別する必要がある場合は、ビューを作成します。 「書籍」と同じ内容の「オーディオブック」が同じISBNを持っているかどうか確認しましたか?

+2

あなたの答えは技術的に正しいとはいえ、私はそれに従うべきではないと思います。 PostgreSQLではこれをきれいにモデリングすることができます。複数のオブジェクトをまとめて1つのテーブルにまとめると、大きな混乱が生じることがあります。 – Theuni

関連する問題