Database Design: Circular dependency
-
21-09-2019 - |
Question
Imagine the following database:
Table 'companies' has fields id, name and flagship_product_id. Table 'products' have fields id, name and company_id.
A company must have a flagship product (1:1 relationship) and all products have one company (1:N relationship).
When using a storage engine such as MyISM, there shouldn't be any problem with the above scenario, but when using an engine such as InnoDB, problems result when INSERTing new data.
What is a good solution except allowing a NULL relationship for the initial INSERT?
To summarize, A company must have one flagship product.
Solution
I don't know that particular database engine, but search for a way to temporarily suspend the data consistency checks or referential integrity during your atomic insert and update operations.
OTHER TIPS
You're either going to have to allow NULLs in flagship_product or reconsider how you model this situation. Consider putting flagship_product as a boolean field on product instead. Then you don't have a circular dependency. Or have a product_type field on product that might have values like FLAGSHIP or NORMAL or OBSOLETE or whatever. Of course you have to enforce that but in the past I've found it a cleaner solution to this kind of problem.
I recommend using the following data model:
COMPANIES
- COMPANY_ID pk
PRODUCTS
- PRODUCT_ID (pk)
- COMPANY_ID (fk)
FLAGSHIP_PRODUCTS
- COMPANY_ID (pk, fk)
- PRODUCT_ID (fk)
Creating a FLAGSHIP column in the PRODUCTS
table will not ensure that only one product is the flagship product for the given company because:
- A unique key on the FLAGSHIP column requires the values to be different from each other
- A check constraint is only a list of acceptable values
why not put a flagship product field into the products table as a boolean... you could index that and companyid and have a pretty quick lookup
The only products that are smart and powerful enough to deal with such situations correctly are systems that fully embrace/implement the concept of Multiple Assignment.
There is not a single SQL system plays in that league.
EDIT
SQL systems have deferred constraint checking, but using that can get messy.
Here's an outline of a possible work-around. I'm not sure how high on the Kludge scale this fits, but it's up there.
- Create Database
- Create clients and products tables
- Insert a placeholder or "dummy" row in each, configured to reference each other
- Establish FK constraints between the tables
Thereafter, whenever a client or product is created, IF the proper referenced product/company has not yet been created, you initialized the new item to point to dummy placholder. Next you enter that item, and you complete by updating the first entry.
The upside is, you have absolute referential integrity once your database initialization routine is completed--and you only run that once under presumably very controlled circumstances, so watch it closely and make sure it doesn't fail! The not downside is, you now have an "extra" item in each table cluttering up your system.
You'll need to break the cycle by deferring one of your referential integrity constraints until the end of the transaction.
Please google for "INITIALLY DEFERRED DEFERRABLE".
(not sure whether InnoDB supports this)