web-dev-qa-db-ja.com

2つの異なるテーブルの主キーを参照するPOSTGRESQL外部キー

BooksとAudiobooksの2つのテーブルがあり、どちらも主キーとしてISBNを持っています。 Books and Audiobooks ISBNへの外部キー制約を持つisbn属性を持つテーブルが作成されました。私がwrittenbyに挿入したときに発生する問題は、postgresqlが私がwritebyに挿入したISBNがブックとオーディオブックの両方にあることを望んでいることです。著者とその著者が書いた本/オーディオブックを格納するテーブルを作成することは、私には理にかなっていますが、これはpostgresqlのテーブルには変換されません。私が実装しようと考えている代替ソリューションは、2つの新しい関係audiobook_writtenbyとbooks_writtenbyを持つことでしたが、それが良い代替案であるかどうかはわかりません。 2つの異なるテーブルを参照して単一のテーブルを作成するというオリジナルのアイデアをどのように実装するか、またはデータベースをより適切に設計する方法について教えてください。さらに情報が必要な場合はお知らせください。

28
Jason Zhu

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

テーブルの継承を使用して、両方の利点を最大限に引き出すことができます。 writtenbyテーブルを参照する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

これを行う場合は、おそらく、writefbyテーブルにBEFORE INSERTトリガーを追加する必要があることに注意してください。

7
kgrittn

RDBMSは、ポリモーフィック外部キー制約をサポートしていません。やりたいことは合理的ですが、リレーショナルモデルでうまく対応できず、ORMシステムを作成する際のオブジェクトリレーショナルインピーダンスミスマッチの実際の問題の1つではありません。 ウォードのWIkiに関するこれについての良い議論

問題への1つのアプローチは、別個のテーブルknown_isbnsを作成し、BooksとAudioBooksに制約やトリガーを設定して、テーブルに両方のタイプ固有のブックテーブルのすべての有効なisbnsが含まれるようにすることです。次に、writedbyに対するFK制約は、known_isbnsに対してチェックします。

6
dbenhur