2012-04-09 101 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

相关问题