Database optimization/normalization - foreign key appearing in "too many" tables - mysql

I have done quite a lot of research and I believe that my database is in the 4th NF (was told that there is no need to go any further) but something still feels wrong.
I have a table TRUNK to which two tables refer via a foreign key: RATECARD as one trunk can be used in many ratecards (the differentiation being times when valid, callplans etc); furthermore I have a RATEBUYINGINFO which is basically info that you download from the trunk providers and contains info on rates to different destinations and similar. Obviously more RATEBUYINGINFO objects can be associated with one trunk as the price change over time, but the RATEBUYINGINFO and RATECARD are in no direct connection except that they may refer to a single trunk, so I have TrunkID as foreign key in both these tables.
Then I have the info with the selling rates (RATESELLINGINFO table) based on certain RATECARD and also destination info together with the trunk info all of which is kept track of in the RATEBUYINGINFO table (and no, I don't see the point in singling out DESTINATION as a separate table as different trunks by different providers do not provide unique destination names) so I have foreign keys RateCardID and RateBuyingInfoID as foreign keys in RATESELLINGINFO table.
Now the problem is that via these two foreign key the last table has access to two TrunkID values (one in RATECARD and one in RATEBUYINGINFO) which should always be the same (obviously one selling rate refers to a single trunk) but the database architecture won't guarantee that in any way.
Is there an elegant solution to this problem?

When you ask questions like this, always include SQL CREATE TABLE statements and some sample data as SQL INSERT statements. SQL is much more reliable and less ambiguous than your comments. (You can edit your question and add that stuff now to get better answers from people who read this later.)
The trunk id in both the tables RATECARD and RATEBUYINGINFO should probably be part of the primary key or part of a unique constraint in both those tables. If it is, then you can store trunk id once in RATESELLINGINFO with overlapping foreign key constraints. Something like
...
foreign key (trunk_id, rate_card_id)
references ratecard (trunk_id, rate_card_id),
foreign key (trunk_id, rate_buying_info_id)
references rate_buying_info (trunk_id, rate_buying_info_id)
...
Trunk id would have ended up in RATESELLINGINFO anyway (probably) if you'd done a full relational model.
Additional tip: drop the word "info" from your table names. All tables contain info; adding that to the name is just noise.

Related

Are these too many foreign keys?

I'm using MySQL and have been planning out the database structure for a system I'm building out. As I've been going along, I started to wonder if it was acceptable to have a particular foreign key constraint in many different tables. From what I understand, it would be fine, as it makes sense. But I'd like to double check.
For example, I have a users table, and I use the user_id as a foreign key for many tables, sometimes multiple times in one table. For example, I have a one-to-one relationship with a user_settings table, which of course stores the user_id. And then I have a companies table, which alone has a few references to the user_id key. In this case, I have a column that keeps track of the user that created the company in the system (created_by), a column for the main contact (main_contact, who is also a user of the system), and there might be another reference. So that alone, already has the user_id key being used as a foreign key constraint 3-4 times.
Just to add another bit of info, I have a tasks table and that of course needs to reference the user_id to keep track of who it's assigned to, and I also have another column that keeps track of the user that created the task. That would be assigned_to and created_by, respectively.
There are more tables though that reference back to that key. I might be up to 8 references already. I do believe I've designed it properly so far, but based on what I've mentioned, does this sound fine?
Your foreign key usage seems fine to me - after all, you are simply representing logical relationships between your tables.
A user within your system interacts with the data in many ways, and to define these relationships your approach is the correct one.
The key point I think is that under a lot circumstances, you won't always want (or need) to make all the joins that represent your relationships - simply the ones that you need in that context.
As per my undestanding the way you are defining is fine i.e to use a user id to many tables as foreign key.
If your line:: I have a companies table, which alone has a few references to the user_id key doesn't mean that you are using multipe user_id in same table and I know you are not.

Duplicating MySql Column Values VS Foreign Key - Best Practice

We are currently in the process of developing our own e-commerce solution, as part of our research we have been examining the ZenCart Database Schema and found that data is quite frequently duplicated between various tables where it would seem that perhaps a Foreign Key would have been sufficient to link the two or more tables in question, for example:
Given that there is table "Products" that has the following columns
PRODUCT_IDPRODUCT_NAMEPRODUCT_PRICEPRODUCT_SKU
Then if there is a Sales_Item "Table" Then of course a product (and all its constituent columns)may be referenced by simply doing something like:
SALES_ITEM_IDProducts_PRODUCT_ID //This is the foreign key that relates a specific product to a sale item.SALE_TIMEREST_OF_SALE_SPECIFIC_DATA......
However instead it seems that the Sales table COPIES many of the field values defined in the Products table so it infact looks as follows:
SALES_ITEM_IDPRODUCT_IDPRODUCT_NAMEPRODUCT_PRICEPRODUCT_SKUSALE_TIME
My question is which approach would generally be considered best practice when attempting to build a scalable efficient solution. Using foreign keys means data is not duplicated but the caveat is that database or application-level JOINS would be needed in order to query the entire dataset. However than being said, for some reason the foreign key approach seems cleaner and more correct somehow.

Renaming foreign keys to fit the context of a table

When using a foreign key in a table, is it good form to change the name of the key for that table to make it clear what function the key performs in the table, or is it good form to retain the original name, to make it clear that it is a foreign key?
Example:
a table keeps track of users, the primary key is user_id
a second table stores articles on the website and keeps track of the author with the foreign key user_id.
In the context of the second table it would make more sense to call the foreign key author. In the context of the whole database it would make more sense to call the foreign key user_id
Is there a general convention that deals with this situation, or is that what comments are for?
Well, if you have a movie table you wouldn't want columns called person_id and person_id, but rather producer and director, or perhaps producer_id and director_id, or maybe producer_person_id and director_person_id.
I know movies can have multiple directors and multiple producers; this was just an example. Any case in which a table has two foreign keys to the same table will show you that you cannot in principle stick completely to a convention of using only the table name in the column name. You can use both (as in the producer_person_id example) but that leads to long column names.
Don't use comments. No one reads them. Okay that was just snark, perhaps, but in general favor descriptive names to comments!
Aside from the two-foreign-key issue, I'm not really aware of any univerally accepted convention.
It is conventional to know the database schema's modelling and designing. Whatever makes sense to the database administrator. Business logic is not concerned with how the database is named, only the results. For the database administrator if it make more sense to rename the foreign key author_id to refer to user_id of another table then do so and notate it in some documents that T2.author_id must exist in T1.user_id. When transitioning from modelling to designing the database (which is where you are now) it would make sense to just keep it simple, but you can change the foreign key names so long as you can remember them (and document them as well).

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.

No foreign key constraints and need to do a complicated delete

I have a website which I have been working on creating very rapidly, and now am paying back some technical debt. I have a complicated issue:
My site deals with scheduling hikes. Once you create a hike, it has many things associated with it:
a message board, list of attendees, the group it belongs to, the carpool, route, trailhead, etc.
Here is an example so you can see what I am talking about:
http://www.comehike.com/hikes/scheduled_hike.php?hike_id=172
The technical debt I am talking about is that I never made foreign keys in the DB, and now need to do a cascade delete, and I am not sure how to go about it so that I don't introduce a million bugs :)
Should I make foreign keys for all the tables now? How should I do this?
Thanks,
Alex
Check out the MySQL docs on FOREIGN KEY Constraints. Note that you'll need to be using innoDB tables.
ALTER TABLE <tablename>
ADD CONSTRAINT <fkname> FOREIGN KEY <index name>(<columns>)
REFERENCES <othertable> (<columns>)
ON DELETE CASCADE
I would suggest creating foreign keys for the tables in your DB. This will be a more robust way of dealing with the problem you are facing. You obviously understand what a foreign key imposes on the database, and how to deal with the keys.
If I was faced with this problem, I would use a graphical interface for the database if I had one (e.g. PhpMyAdmin), otherwise a quick google brings up some tutorials.
EDIT: From the linked tutorial, in a many-to-one relationship, you pace the key on the "many" table, indicating that a certain column in that table can only have values that are present in a certain column in the "one" table. Hi the link for a worked example.
When adding keys to a table that already has data, you may not be able to add the foreign key if some of the data is malformed. For example, if you have a phone number table referencing a person table (many phone numbers to one person) and you have any phone numbers with an invalid person_id (maybe person 5 was deleted and there is still a phone number with a person_id of 5) you will be unable to create the foreign key until you remove the offending phone number.
if you have not made formal foreign keys, the have you made the keys some other way that permits linking the tables or are all tables unrelated ?
If there is anyway to relate the tables then you will simply have to write a Cascading Delete code.
Otherwise its probabely a redesign or add in foreignkey fun. =))
If you have not already get yourself a copy of MySQL Workbench and redesign it from there adding in the foreign keys. This will generate the SQL code for you too.
I would go with creating foreign keys as well but if there is any reason that stops you from doing so there is another solution which is creating Triggers. You can tell triggers to basically do anything you want when an update,delete or insertion occurs to a table in the database including changing other tuples in other tables. Here are a couple of tutorials on how to create triggers:
http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_7004.htm
http://msdn.microsoft.com/en-us/library/ms189799.aspx
the first one seems more direct and clearer but if none of them helps just search google for DB triggers and you're all set!
I hope this helps :)