I'll be using Postgres for the examples, but feel free to show examples in other databases if needed.
The simplified schema:
create table factory (
id serial primary key,
detail text not null
);
create table process (
id serial primary key,
detail text not null
);
create table item (
id serial primary key,
detail text not null
);
I'll refer Factory as [F], Process as [P] and Item as [I].
The schema has the following conceptual relationships:
- Each Process is exclusive to one Factory, so [P] n -> 1 [F]
- Each Item is exclusive to one Factory, so [I] n -> 1 [F]
- Each Item can be made by multiple Processes, so [P] n -> 1 [I]
To express this relationships I came up with:
create table factory_item_process (
factory_id integer not null references factory(id),
process_id integer not null references process(id),
item_id integer not null references item(id),
constraint pk_factory_item_process primary key (
factory_id, process_id, item_id
),
constraint uq_factory_item_process_process unique (process_id)
);
This takes care of [P] n -> 1 [I]
and [P] n -> 1 [F]
, but doesn't solve [I] n -> 1 [F].
There is no way to convey [I] n -> 1 [F]
with unique key constraints, so I created a simple function that checks if [I] already belongs to an [F]:
create function in_other_factories(
factory_id integer,
item_id integer
) returns boolean
language sql returns null on null input
return true in (
select
true
from factory_item_process
where factory_id <> $1
and item_id = $2
);
alter table factory_item_process
add constraint chk_factory_item check(not in_other_factories(factory_id, item_id));
What is right & wrong about this to express these relationships?
Making a check with a user-defined function is a code smell.
I don't if the tables are correctly normalized. I chose to use another table for this relationship because this relationship will have attributes that are exclusive to itself.