Du har utelämnat alla främmande nycklar på boknamnet.
Det är därför jag svarar med en komplett förbättrad uppsättning tabelldefinitioner, det här handlar om främmande nycklar, eller hur? Visst, du gav ett avskalat exempel.
Problemet att lösa var att poster i reading_event_discussion
måste handla om teman som finns i den boken:
drop table book cascade;
drop table book_theme;
drop table reading_event cascade;
drop table reading_event_discussion;
create table book (
name text primary key -- new, a must because it is FK in reading_event
);
insert into book (name) values ('game of thrones'),('Database design');
create table book_theme (
bookname text references book(name), -- new
themename text
);
insert into book_theme (bookname, themename) values
('game of thrones', 'ambition'), ('game of thrones', 'power');
create table reading_event (
i SERIAL primary key,
venue text,
bookread text references book(name) -- FK is new
);
insert into reading_event (venue, bookRead) VALUES
('Municipal Library', 'game of thrones');
-- this is the solution: extended reference check
create or replace function themecheck (i integer, th text) returns boolean as $$
select
(th in (select themename from book_theme bt
join reading_event re on i=re.i and re.bookRead=bt.bookname))
$$ language sql;
create table reading_event_discussion (
i integer references reading_event(i),
themeDiscussed text check (themecheck (i, themeDiscussed))
);
-- Test statements:
-- just check data
select * from reading_event;
-- this should be ok
insert into reading_event_discussion values (1,'ambition'),(1,'power');
-- this must be refused
insert into reading_event_discussion values (1,'databases');
Så lösningen är att skriva en anpassad kontrollfunktion. Detta är inte portabelt till andra databassystem.
Man kan skriva den här funktionen på flera språk (plpgsql, pltcl, ...), men SQL-funktioner kan infogas i en fråga och kan vara snabbare.