I’m facing this problem:
I have a parent table, and a child table, one parent can have multiple children, standard story.
These are the constraints:
- each parent must have at least one child,
- each parent must have one favourite child,
- each parent can have one least-favourite child
How to desing this in SQL?
I’m not sure the standard parent-child tables can be used because of the circular relationship:
Parent table:
parentId
favouriteChildId NOT NULL
leastFavouriteChildId NULL
Child table:
childId
parentId
I was thinking of using a bridge table, but am not sure how to model these constraints.
EDIT: Just to add some clarity, here is part of the problem context:
There is the Price table (child), and PriceGroup table (parent).
PriceGroup has multiple prices, one mandatory mainPrice (favouriteChild) and can have one officialPrice (leastFavouriteChild).
The following is not related to the problem, but sheds some light on the context:
Prices are grouped according to Products they refer to, and one Product can have multiple prices – these are then grouped in price groups, and each group needs reference to a main price, and an official price (if there is one).
Out of the business rules that you have given
Your solution of
satisfies 2 and 3.
But also it satisfies the 1 (since favouriteChildId NOT NULL will not allow creating parent records with no children).
Since you already have the above, I will assume that the real question for you is how to make parentId in Child table NOT NULL.
Normally, there are provision in SQL so that you could do something like
in that case ‘circular reference’ would not be a problem (see DEFERRED)
Mysql does not support it, so you have following options
Triggers:
It can be assumed that at the time of inserting parent record a favorite child is already known then you can have a trigger that would run before insert on the parent table and
NOTE: Problem is that this way you can formally satisfy the criteria, but to insert the child record first you will have to either use additional columns in parent so that the trigger can know about other fields in child table or insert a blank record (in either case the design is not clean)
Integrity through security
The above can be implemented as stored procedure without requiring additional fields on Parent table level. However stored procedures could, normally be bypassed so it does not qualify as real integrity rule.
There is, a generic way to make something achieved with a stored procedure qualify as integrity rule – and that is to remove write permissions for all regular users (and applications) for these tables and allow the data to be changed only through stored procedure.
EDIT:
Regarding triggers there is also a way to implement the rule with triggers, and that is to accept that you will have to insert records separately and that you can must have, at one moment data that breaks your business rules.
In that case you can have a STATUS atrribute for the parent record (for example: COMPLETE vs INCOMPLETE) and make favouriteChildId a NULLable FK, but when updating the status to COMPLETE you can have trigger check that integrity is respected.
This requires additional column but can make things quite clean (you can actually create a view on this table that would only expose only records that are COMPLETE, effectively making it look like the table with FK NOT NULL).