Building on your comments with paxdiablo . . .
Let's look at some SQL. I could have chosen better names for the columns, but I deliberately didn't. I wasn't being lazy; I had good reasons. An external predicate is how users are supposed to interpret the contents of a table.
-- External predicate: Human is identified by
-- Social Security Account Number [ssan]
-- and has full name [full_name]
-- and result of last HIV test [hiv_status]
-- and has checking account [bank_account]
-- and was born at exactly [birth_date].
--
create table human (
ssan char(9) primary key,
full_name varchar(35) not null,
hiv_status char(3) not null default 'Unk'
CHECK (hiv_status in ('Unk', 'Pos', 'Neg')),
bank_account varchar(20),
birth_date timestamp not null
);
-- External predicate: Human athlete identified by
-- Social Security Account Number [ssan]
-- has current doping status [doping_status]
create table athlete (
ssan char(9) not null primary key references human (ssan),
doping_status char(3) not null default 'Unk'
CHECK (doping_status in ('Unk', 'Pos', 'Neg'))
);
-- External predicate: Human dictator identified by
-- Social Security Account Number [ssan]
-- has estimated benevolence of [benevolence_score].
create table dictator (
ssan char(9) not null primary key references human (ssan),
benevolence_score integer not null default 3
CHECK (benevolence_score between 1 and 5) -- 1 is least, 5 is most benevolent
);
All three of those tables are in 5NF. (Which means they're also in 3NF.)
You said
there is no "IS A"-relationship in a
relational database
An athlete "IS A" human, because its identifier is a human identifier. In this case, its primary key is a foreign key that references human (ssan)
. Database designers don't usually talk in terms of "IS A" and "HAS A" relationships, because predicates are more precise and expressive. You can see the difference by comparing these two statements.
- human "HAS A" [birth_date]
- human was born at exactly
[birth_date]
That last one is deliberately a little jarring. I defined the birth_date column as a timestamp--it accommodates both date and time. It illustrates how external predicates are to some extent independent of the column names. (It also illustrates how the loose coupling between predicates and column names might not be such a good idea here.)
You said
But now you nerver get a pure HUMAN
but only children of HUMAN
I'm not sure what you mean by "pure human". You can get all the humans by simply
SELECT * FROM human;
If you mean that you can't have a human unless the human is an athlete or dictator (or whatever), then you're mistaken. If there's no row in athlete for a specific SSAN, then the human identified by that SSAN isn't an athlete. If there's no row in dictator for a specific SSAN, then the human identified by that SSAN isn't a dictator.