On the project I am working on I have a table that needs to be defined as having a one to nine relationship and I was wondering what the best way of creating that in the database was? I am working in PostgreSQL.
My original idea was to create a table and just explicitly create the links (note that actual_id is because of the system I have to virtualize the id because I need unique tables but I also need to know what the actual id of the template is)
CREATE TABLE template (
id int,
actual_id int,
foreign_key0 int references other_table(id),
foreign_key1 int references other_table(id),
foreign_key2 int references other_table(id),
foreign_key3 int references other_table(id),
foreign_key4 int references other_table(id),
foreign_key5 int references other_table(id),
foreign_key6 int references other_table(id),
foreign_key7 int references other_table(id),
foreign_key8 int references other_table(id)
);
However this is creating an issue when I want to clean the data from the referenced table when nothing is being referenced anymore. Also I was pretty positive that this was bad db design from the beginning.
My other idea is that I would just make the table with one constraint
CREATE TABLE template (
id int,
actual_id int,
foreign_key0 int references other_table(id) );
However the problem here is how do I constrain this to only have 9 references to the other table? Stored procedures? Programmatically?
Ultimately if I stick with the first way I am pretty sure I am just going to have to select all of the different foreign_key’s into another table that just has a single column and compare that against other_table’s id. I don’t want to do this. It seems really dumb. I really want to do it the second way but I have no idea how to best go about this.
A 1:n relationship can always be reversed to be seen as n:1 . In other words, instead of:
you can always write:
… and constrain the number of children per parent via a trigger or in the application. That’s the approach I would strongly recommend. You’ll need a deferrable constraint trigger to allow you to insert anything.
If you want to enforce it in the database, use a constraint trigger. Given the dummy schema:
You could write:
Note that there are two triggers above. The trigger on child is obvious. The trigger on parent is needed to prevent insertion of a parent without any children.
Now observe a test:
Because the deferred constraint trigger is checked when the transaction commits, not immediately or at the end of the statement, you can still do this:
… but if you change the “generate_series” max to 8 or 10, or leave off inserting any children entirely, COMMIT will fail like, eg:
If you only require each parent to have a maximum of 9 children, not exactly 9 children as implemented in the above trigger, you can remove the
DEFERRABLE INITIALLY DEFERRED, change the<> 9to<= 9, and chop out theDELETEhandler in thechildtrigger.BTW, if I were working with JPA in Java or some other reasonably clever ORM I’d just constrain the size of the collection of children on the parent:
Way simpler, albeit not enforced at the database level.