What is the best way to insert rows into tables with references 1 to 1 of each other?
I mean, in a MySQL 5.5 and tables InnoDB, I have a database design similar to the following
The problem arises when we try to insert rows in table1 and table2. Since there is no multi-table insert in MySQL, I can not insert a row becouse the foreign keys are NOT NULL fields in both tables and should be inserted simultaneously in both.
Which is the bes way to solve this problem?
I have in mind 3 possible solutions, but I want to know if there are more than these or which is the best and why.
Set the foreign key field as NULLABLE and after insert one row in a table, insert the other one and afterwards, update de first one.
Just as indicated above but with an special value like -1. First, insert in one table with foreign
key = -1
that is equivalent to NULL but avoiding set the field as NULLABLE. Afterwards, we insert the row in the other table and update the first one inserted.Create a relational table between both though it is not really necessary because it is a 1 to 1 ratio
Thanks!!
EDIT I briefly explain what I need this circular relationship: It is a denormalization from the parent table to one of its childs. It is made in order of high performance to have always the reference of the best ranked child from a parent table.
I'll make this an answer as I feel this is a design flaw.
First, if the two tables are in true
1:1
relationship, why don't you just have one table?Second, if it's not a true
1:1
relationship but a supertype-subtype problem, you don't need this circular foreign keys either. Lets saytable1
isEmployee
andtable2
isCustomer
. Off course most customers are not employees (and vice-versa). But sometimes a customer may be an employee too. This can be solved having 3 tables:In the scenario you describe you have two tables
Parent
andChild
having1:N
relationship. Then, you want to store somehow the best performing (based on a defined calculation) child for every parent.Would this work?:
This way, you enforce the wanted referential integrity (every BestChild is a Child, every Parent has only one BestChild) and there is no circular path in the References. The reference to the best child is stored in the extra table and not in the
Parent
table.You can find BestChild for every Parent by joining:
Additionally, if you want to store best children for multiple performance tests (for different types of tests, or tests in various dates), you can add a
test
field, and alter the Primary Key to(test, parentid)
:I'd create a blackhole table and put a trigger on that to take care of inserts
and put a trigger on that to take care of inserts
Note that actions in a trigger are part of one transaction (when using InnoDB or likewise), so an error in the trigger will rollback partial changes.
Note on your table structure
Note that if it's a 1-on-1 table, you only need to put a table2_id in table1 and no table1_id in table2 (or visa versa).
If you need to query table1 based on table2 you can just use:
Likewise for the other way round
Links:
http://dev.mysql.com/doc/refman/5.1/en/blackhole-storage-engine.html
http://dev.mysql.com/doc/refman/5.1/en/triggers.html
I feel this is an important question, and I haven't found any 100% satisfying answer throughout the web. The 2 answers that you have given are the best ones I found, yet they are not 100% satisfactory.
Here's why :
The reason why Emilio cannot put his best child inside his parent table is pretty simple, I presume, because I share the same problem : not every child will be labelled as a parent's best child. So he would still need to store information on other children somewhere else. In that case, he would have some information about the best children in their parent's table, and other children in a separate database. This is a huge mess. For example, the day he wants to change the data structure about children, he needs to change it in both tables. Every time he writes a query on all children, he should query both tables, etc...
the reason why Emilio cannot just set the best child foreign key to nullable (I presume for Emilio, but for me it would be very strict), is that he needs to be sure that a parent always has a best child. In Emilio's case it's maybe not very easy to imagine, but in mine, I cannot have the equivalent of the parent have no child.
Thus I would have tended to think that the solution with setting foreign_key_checks to zero would be best, but here is the problem :