2012-04-09 150 views
13

我有兩個表格和有聲讀物,它們都以ISBN爲主鍵。我有一個表格,它有一個isbn屬性,它有一個外鍵約束書籍和有聲讀物ISBN。當我插入到書面時出現的問題是,postgresql想要我插入到書寫的ISBN中以便出現在書籍和有聲讀物中。對於我來說,有一個由商店作者和他們編寫的書籍/有聲讀物編寫的表格是有意義的,但是這並不會轉化爲postgresql中的表格。我正在考慮的另一種解決方案是有兩個新的關係audiobook_writtenby和books_writtenby,但我不確定這是一個好的選擇。你能否告訴我如何實現我最初的想法:通過引用兩個不同的表來寫一張表,或者如何更好地設計我的數據庫。如果您需要更多信息,請與我們聯繫。POSTGRESQL外鍵引用兩個不同表格的主鍵

回答

4

RDBMS不支持多態外鍵約束。你想要做的事情是合理的,但是在關係模型中並沒有很好地適應這種情況,並且在製作ORM系統時不能很好地解決對象關係阻抗不匹配的實際問題之一。 Nice discussion on this on Ward's WIki

解決問題的一種方法可能是製作單獨的表known_isbns,並在Books和AudioBook上設置約束和/或觸發器,以便表包含這兩種類型特定書籍表的所有有效isbns。然後你寫的FK約束將檢查known_isbns。

+3

關係模型和SQL數據庫實際上處理這種事情。問題不是關係型或SQL;問題在於其中一個顯而易見的限制是錯誤地實現的。 (約束條件是書籍和有聲讀物的ISBN是從相同的域中抽取的。) – 2012-04-09 18:17:17

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觸發器。

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

在這個特定的例子中,絕對不需要使用多個表。只要使用表格「Book」並添加「AudioBook」的列(如果適用)即可。如果您必須在具有特定列的表級別上進行區分,請創建視圖。您是否檢查過具有相同內容的「書」和「音頻書」是否具有相同的ISBN?

+2

即使你的答案在技術上是正確的,但我不認爲應該遵循它。 PostgreSQL支持非常好的建模。把多個物體摺疊成一張桌子通常會變成一團糟。 – Theuni 2016-09-23 19:19:43

相關問題