POSTGRESQL外键引用两个不同表的主键

x6yk4ghg  于 2023-03-01  发布在  PostgreSQL
关注(0)|答案(4)|浏览(176)

我有两个表Books和Audiobooks,这两个表的主键都是ISBN,还有一个表writtenby,它的isbn属性对Books和Audiobooks的ISBN有一个外键约束。
当我插入到writtenby中时出现的问题是postgresql希望我插入到writtenby中的ISBN同时出现在书籍和有声读物中。
对我来说,有一个表writtenby来存储作者和他们写的书/有声读物是有意义的,但是这并不能转化为postgresql中的表。
我正在考虑实现的替代解决方案是拥有两个新关系audiobook_writtenbybooks_writtenby,但我不确定这是否是一个好的替代方案。
你能给予我如何实现我最初的想法,让一个表writtenby引用两个不同的表,或者我如何更好地设计我的数据库吗?如果你需要更多的信息,请告诉我。

soat7uwm

soat7uwm1#

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

qxsslcnc2#

你可以使用表继承来达到两全其美的效果。创建audiobook_writenby和books_writenby,并使用INHERITS子句引用writenby表。外键可以像你描述的那样定义在子级,但是你仍然可以在更高的级别引用数据。(你也可以使用视图来实现这一点,但是在这种情况下,听起来继承可能更干净。)
参见文档:
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
注意,如果这样做,您可能需要在writenby表上添加一个BEFORE INSERT触发器。

ttcibm8c

ttcibm8c3#

RDBMS不支持多态外键约束。您想要做的是合理的,但关系模型不能很好地适应,并且在创建ORM系统时对象关系阻抗不匹配是一个真实的的问题。Nice discussion on this on Ward's WIki
解决问题的一种方法是创建一个单独的表known_isbns,并在Books和AudioBooks上设置约束和/或触发器,以便该表包含两个类型特定的book表的所有有效isbns。然后,writenby上的FK约束将检查known_isbns。

6yjfywim

6yjfywim4#

在这个特定的例子中,绝对没有必要使用多个表。只要使用表“Book”,并添加“AudioBook”中的列(如果适用的话)。如果您必须在表级别上区分非常特定的列,请创建视图。您是否检查过内容相同的“Book”和“Audio Book”是否具有相同的ISBN?

相关问题