Two-way foreign key constraint in a 1:1 relation - mysql

I am using a MySQL database. In my relational data model, I've got two entities that relate 1:1 to each other. In my schema, a 1:1 relation is set up by putting a FK field in one of the two tables, that relates to the PK of the other table. Both tables have PKs and they are both auto increment BIGINTs.
I am wondering whether it would be possible to have an ON DELETE CASCADE behaviour on them that works both ways.
i.e. A 1:1 B, means that [ deleting A also deletes B ] as well as [ deleting B also deletes A ].
I realise that this may not be absolutely necessary in terms of proper application design, but I am just wondering whether it is actually possible. As far as I recall, you can't put an FK constraint on a PK.

It'd be impossible to insert such records if you have a 2-way relationship enforced. Chicken-and-egg. Record in table #1 can't be inserted because there's no matching record in table #2, and table #2 cannot be inserted into because there's nothing in table #1 to hook to.
You can disable FK constraints temporarily (set foreign_key_checks = 0), but this should never be done in a "real" system. It's intended more for loading dumps where the table load order cannot be guaranteed.

Related

Multi-tenant database with tenant ID on every table

Would there be any value in adding a FK for OrganizationID to the Group_Scopes table? Normalization standards would say no because the relationship is transitive, but the general rule of thumb for multi-tenant with row level security seems to dictate you add the tenant id to every table.
Yes, generally foreign keys help guarantee referential integrity via constraints.
Also you can perform CASCADE operations (you can delete or update the row from the parent table, and MySQL will automatically delete or update the matching rows in the child table)
So, if you'll have a lot of tables (or tables with complex structures) using FK would be helpful because it will prevent from you making necessary checks using any other programming languages - MySQL will do it by itself

What can I do with a foreign key that I can't with JOIN in a SQL statement?

They say a foreign key is to make possible a relationship between two tables, but I can do this in my statements with JOINs. Exactly what can I do with a foreing key in a SQL statement that I can't do with a JOIN? Or is a foreign key only to help us while we are working with tables in the database?
Relationships between rows of two tables can be established by storing a "common value" in columns of each table. (This is a fundamental tenet of relational database theory.)
A FOREIGN KEY is an integrity constraint in the database. If there is a foreign key constraint defined (and enforced), the database will prohibit invalid values from being stored in a row (by INSERT and UPDATEstatement, and prevent rows from being removed (by DELETE statement.)
A JOIN operation in a SQL statement just allows us to access multiple tables. Typically, a join operation will include conditions that require a "match" of foreign key in one table with a primary key of another table. But this isn't required. It's possible to "join" tables on a huge variety of conditions, or on no condition at all (CROSS JOIN).
A foreign key is designed to protect database integrity. You can read data with a join without any foreign key being present (and we do it all the time).
What a foreign key will do is prevent you form corrupting your data by doing things like deleting the parent record that a child record refers to. If you attempt to delete the parent record without deleting the child first, it will error, preventing the data corruption. It can also be configured so that if you delete the parent, child records are automatically deleted.
We don't use FKs (foreign keys) to query or update.
Tables represent application relationships. When some values or entities identified by values are related in a certain way we put that row in the table for that relationship. We get or put rows that participate in relationships combined from base table relationships by writing queries mentioning the base tables. JOIN of tables returns the rows that are related by one's relationship AND by the others. UNION returns the rows that are related by one's relationship OR the other. ON and WHERE become AND. Etc. (Is there any rule of thumb to construct SQL query from a human-readable description?) By setting columns equal we force the same value or entity to play roles in multiple relationships. There might or might not be a FK between them, but we don't need to know that to query or update.
FKs get called "relationships", but they're not. They are facts. (They are also "instances" from a "meta" relationship on tables & columns.) They state that the subrow values for some columns in a table are always also subrow values for some columns that are PRIMARY KEY or UNIQUE in some table. (This also means that a certain implication using the tables' relationships is always true in the application situation.) Declaring a FOREIGN KEY to the DBMS means that it can reject update attempts that don't satisfy that constraint as errors. FK declarations are also tied to CASCADE rules in SQL DBMSs, simplifying updates.

What is the cost of deletion of a record from a Child table having foreign key constraint with parent table

For instance there are 20 tables which have foreign key of a table let's call it Child. Now when i delete a record from Child it will check whether the record is referenced from somewhere or not, is it so or some other scenario.
My question is how this foreign key relation impacting performance of deletion operation.
Actually i'm using hibernate and i have an entity which has got only 3 columns and is used in many other Entities(one-to-one) mapping.
I'm thinking to make this entity embeddable for performance tuning because if i keep it entity then mapping between tables is done using foreign key. Although when i delete an entity there are only two query are running :- delete parent , then delete child. But as child's foreign key is referenced from many other tables with lot of records so it will check whether reference of record in child exists in some tables or not if not then delete while deleting child record. So i want to target this issue by making child embeddable which will result columns of child will be included in parent tables. Whether this will help?
Performance depends very much on which DBMS you're using, how your tables are designed, indexed and stored, and how much data you have.
In general, foreign key constraints save time and effort and prevent mistakes. Without a foreign key constraint, you would have to enforce integrity yourself.
For example, manually cascading a delete or update would be done in multiple round-trips to the database which would normally be wrapped in a transaction. Manually checking for related records to restrict changes would also require additional queries and data transferred between server and client.
If you missed anything or another user modified related data between your queries, you might end up with invalid data, which can be very costly - both in terms of DBA time as well as customer satisfaction.

Database Design - Custom attributes table - Table that "relate" entities

I'm designing a database (for use in mysql) that permits new user-defined attributes to an entity called nodes.
To accomplish this I have created 2 other tables. One customvars table that holds all custom attributes and a *nodes_customvars* that define the relationship between nodes and customvars creating a 1..n and n..1 relationship.
Here is he link to the drawed model: Sketched database model
So far so good... But I'm not able to properly handle INSERTs and UPDATEs using separate IDs for each table.
For example, if I have a custom attribute called color in the *nodes_customvars* table inserted for a specific node, if I try to "INSERT ... ON DUPLICATE KEY UPDATE" either it will always insert or always update.
I've thinked on remove the "ID" field from the *nodes_customvars* tables and make it a composite key using nodes id and customvars id, but I'm not sure if this is the best solution...
I've read this article, and the comments, as well: http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary_keys.aspx
What is the best solution to this?
EDIT:
Complementing: I don't know the *nodes_customvars* id, only nodes id and customvars id. Analysing the *nodes_customvars* table:
1- If I make nodes id and/or customvars id UNIQUE in this table, using "INSERT ... ON DUPLICATE KEY UPDATE" will always UPDATE. Since that multiple nodes can share the same customvar, this is wrong;
2- If I don't make any UNIQUE key, "INSERT ... ON DUPLICATE KEY UPDATE" will always INSERT, since that no UNIQUE key is already found in the statement...
You have two options for solving your specific problem of the "INSERT...ON DUPLICATE KEY" either always inserting or updating as you describe.
Change the primary to be a composite key using nodeId and customvarId (as suggested by SyntaxGoonoo and in your question as a possible option).
Add a composite unique index using nodeId and customvarId.
CREATE UNIQUE INDEX IX_NODES_CUSTOMVARS ON NODES_CUSTOMVARS(nodeId, customvarId);
Both of the options would allow for the "INSERT...ON DUPLICATE KEY" functionality to work as you require (INSERT if a unique combination of nodeId and customvarId doesn't exist; update if it does).
As for the question about whether to have a composite primary key or a separate primary key column with an additional unique index, there are many things to consider in the design. There's the 1NF considerations and the physical characteristics of the database platform you're on and the preference of the ORM you happen to be using (if any). Given how InnoDB secondary indexes work (see last paragraph at: http://dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html), I would suggest that you keep the design as you currently have it and add in the additional unique index.
HTH,
-Dipin
You current entity design breaks 1NF. This means that your schema can erroneously store duplicate data.
nodes_customvars describes the many-to-many relationship between nodes and customvars. This type of table is sometimes referred to as an auxiliary table, because its contents are purely derived from base tables (in this case nodes and customvars).
The PK for an auxiliary table describing a many-to-many relationship should be a composite key in order to prevent duplication. Basically 1NF.
Any PK on a table is inherently UNIQUE. regardless of whether it is a single, or composite key. So in some ways your question doesn't make sense, because you are talking about turning the UNIQUE constraint on/off on id for nodes and customvars . Which you can't do if your id is actually a PK.
So what are you actually trying to achieve here???

In MySQL, why do I have to define ForeignKey relationships?

Why can't I just leave those relationships out?
What's the point of them?
I can stil run queries and treat them like it a relationship myself...
Yes, you can always leave the foreign key constraints out but then you will be responsible about the integrity of your data. If you use foreign key constraints, then you won't have to worry about the referential integrity among tables. You can read more about referential integrity from Wikipedia. I will also try to explain it with an example below.
Think of a shopping cart scenario. You have three tables: item, shopping_cart and shopping_cart_item. You can choose not to define any relationship between these tables, that's fine for any SQL solution. When user starts shopping, you create a shopping cart by adding a shopping_cart entry. As user adds items to his shopping cart, you save this information by adding rows to shopping_cart_item table.
One problem may occur at this step: If you have a buggy code that assigns incorrect shopping_cart_id's to shopping_cart_items, then you will definitely end up with incorrect data! Yes, you can have this case even with a foreign key constraint if the assigned id actually exists in the shopping_cart table. But this error will be more detectable when a foreign key exists since it would not insert shopping_cart_item record when the foreign key constraint fails.
Let's continue with the assumption that your code is not buggy and you won't have first type of referential integrity. Then suddenly a user wants to stop shopping and delete the cart and you chose to implement this case by deleting the shopping_cart and shopping_cart_item entries. Then you will have to delete entries in both tables with two separate queries. If something goes wrong after you delete shopping_cart entries, then you will again have a referential integrity problem: You will have shopping_cart_items that are not related to any shopping_cart. You will then have to introduce transaction managing, try to provide meaningful data to your business logic about the error happened in data access layer, etc..
In this type of scenario's, foreign keys can save life. You can define a foreign key constraint that will prevent insertion of any sort of incorrect data and you can define cascade operations that will automatically perform deletion of related data.
If there is anything unclear, just leave a comment and I can improve the answer.
Apart from what the others have said about why you technically want (actually: need) them:
foreign key constraints also document your model.
When looking at a model without FK constraints you have no idea which table relates to which. But with FK constraints in place you immediately see how things belong together.
You create FOREIGN KEYs to instruct the database engine to ensure that you never perform an action on the database that creates invalid records.
So, if you create a FOREIGN KEY relationship between users.id and visits.userid the engine will refuse to perform any actions that result in a userid value in visits that does not exist in users. This might be adding an unknown userid to visits, removing an id from users that already exists in visits, or updating either field to "break" the relationship.
That is why PRIMARY and FOREIGN KEYs are referred to as referential integrity constraints. The tell your database engine how to keep your data correct.
It doesn't allow you to enter an id which does not exist in another table, for example, if you have products and you keep owner Id, by creating a foreign key ton the owner id to id field of the owners table, you do not allow users to create an object record which has an owner id which does not exist in the owner table. such things are called referential intergrity.
The foreign key constraint helps you ensure referential integrity.
If you delete a row in one table, mysql can automatically delete all rows in other tables that the deleted row refers to via the foreign key. You can also make it reject the delete command.
Also when you try to insert a row, mysql can automatically create new rows in other tables, so the foreign key does not refer to nothing.
That is what referential integrity is all about.
Databases can be affected by more than just the application. Not all data changes go through the application even if they are supposed to. People change stuff directly on the database all the time. Rules that need to apply to all data all the time belong on the database. Suppose you can update the prices of your stock. That's great for updating anindividual price. But what happens when the boss decides to raise all prices by 15%. No one is going to go through and change 10,000 prices one at a time through the GUI, they are going to write a quick SQL script to do the update. Or suppose two suppliers join together to have one company and you want to change all of thie items to be the new company. Those kinds of changes happen to databases every day and they too need to follow the rules for data integrity.
New developers may not know about all the places where the foreign key relationships should exist and thus make mistakes which cause the data to be no longer useful.
Databases without foreign key constraints have close to a 100% chance of having bad data in them. Do you really want to have orders where you can't identify who the customers were?
THe FKS will prevent you from deleting a customer who has orders for instance or if you use a natural key of company_name and the name changes, all related records must be changed with the key change.
Or suppose you decide to put a new GUI together and dump the old one, then you might have to figure out all the FK relationships again (because you are using a different datalayer or ORM) and the chances are you might miss some.
It is irresponsible in the extreme to not put in FK relationships. You are risking the lifeblood of your company's business because you think it is a pain to do. I'd fire you if you suggested not using FKs because I would know I couldn't trust my company's data to you.