Database design: When not to use foreign keys? - mysql

I am unsure what is the rule of thumb of when to use foreign keys and when it's better to insert an "unreferenced" value in regard of disk space needed, performance etc.
Let's say I have three tables:
Table 1: itemGroup (for to populate a dropdown menu with items)
ID title
1 Active/Inactive Options
2 Car Brands
3 Ratings
4 Languages
Table 2: item (the itemID will be the actual value in the dropdown and used as a foreign key )
itemID listID title
1000 1 active
1001 1 inactive
1002 2 Porsche
1003 2 Audi
1004 3 1-Star Rating
1005 3 2-Star Rating
1006 4 en
1007 4 de
Table 3: exampleTable
ID car rating active language
So my question is whether I should insert foreign keys in table 3 using the itemID, or would it make more sense to use a 1/0 for active/inactive and to use let's say 1,2,3,4,5 as an integer for the rating? Guess for the car it's quite self explaining that the foreign keys are better but in some cases it's hard to decide as my "item" table can be very big and therefore the itemID has more digits than the actual "value" it might be referring to and in a big database this at some point will make a difference in space and I guess also performance wise because with foreign keys I need to make joints.
UPDATE:
I added the field "language" as maybe here the issue gets illustrated better. So if I'd store a language foreign key (e.g. "1006"):
I need to store over and over a 4-digit int in my exampleTable, instead of just a 2-character varchar
I can't do a an easy query like "SELECT * from exampleTable WHERE language=en"
Why would it be better to use a foreign key here?

Related

Disadvantage of "combined" lookup table in mySQL vs individual lookup tables

Are there big disadvantages (maybe in query speed etc.) of using only ONE combined lookup table (mySQL database) to store "links" between tables over having individual lookup tables? I am asking because in my project scenario I would end up with over a hundred individual lookup tables, which I assume will be a lot of work to setup and maintain. But to make an easier example here is a simplified scenario between only 4 tables:
Table: teacher
teacherID
name
1
Mr. X
2
Mrs. Y
Table: student
studentID
name
4
Tom
5
Chris
Table: class
classID
name
7
Class A
8
Class B
Table: languageSpoken
languageSpokenID
name
10
English
11
German
======================= INDIVIDUAL LOOKUP TABLES ==========================
Table: student_teacher
studentID
teacherID
4
1
5
1
Table: student_class
studentID
classID
4
7
5
8
Table: student_languageSpoken
studentID
languageSpokenID
4
10
4
11
====== VS ONE COMBINED LOOKUP TABLE (with one helper table) =====
helper table: allTables
tableID
name
1
teacher
2
student
3
class
4
languageSpoken
table: lookupTable
table_A
ID_A
table_B
ID_B
1
1
2
4
1
1
2
5
3
7
2
4
3
8
2
5
Your 2nd lookup schema is absolutely unuseful.
You refer to a table by its name/index. But you cannot use this relation directly (tablename cannot be parametrized), you need to build conditional joining expression or use dynamic SQL. This is slower.
Your lookup table is reversable, i.e. the same reference may be written by 2 ways. Of course, you may add CHECK constraint like CHECK table_A < table_B (additionally it avoids self-references), but this again degrades the performance.
Your lookup does not prevent non-existent relations (for example, class and language are not related but nothing prevents to create a row for such relation). Again, additional constraint and decreased performance.
There are more disadvantages... but I'm too lazy to list them all.
Another very important point: Foreign key constraints assuring referential integrity cannot be used in the "combined lookup" approach. They needed to be simulated by complex and error prone triggers. Overall the "combined lookup" approach is just a horrible idea. – sticky bit
There is a rule - non-relational relations must be separated.
In the 1st scheme - does a student may study in more than one class at the same time? If not then you do not need in student_class lookup table, and class_id is an attribute in student table.
Lookup tables are usually static so there shouldn't be much maintenance overhead. If you update the lookup data, however, now have to manage the life cycle of a subset of rows of your single lookup table which may get tricky opposed to just truncating a table when new data becomes available. Where I would be careful if your lookup table have different schemas with columns have to be null as they apply to a given "type" of row. You may not be able to implement the right foreign keys. If you happen to use the wrong id, you would get a nonsensical value. Those help you keep your data consistent (in production systems). If this is school project, especially a database class, you will be dinged for not using textbook normalization.

MySQL two-column table as primary key

I have an extreamly simple idea: table that keeps user "achievements". And it is as simple as that:
user_id | achievement_id
1 | 1
1 | 2
1 | 5
2 | 2
2 | 3
All what I need is user id, and id of achievement if he already got it. All what I need to SELECT is SELECT achievement_id WHERE user_id=x. So no need for an artificial autoincrement column that I'll never use or know what it contains. But setting an primary key is required, so the question is - is it good idea to make such 2-column table and set both columns as multi-column primary key? I already have a set of 3-columns table where 2 are primary key, because it is logic... Well, logic for me, but for the database?
These types of tables are common in cases of n-n relationships, multivalued attributes, and weak entities. It varies a lot from its modeling, but yes, it is a good solution for some cases. the primary key is usually the relation of the columns. In your case it would be user_id and achievement_id.
Yes since the rule for such a set of n-keys is: "I only want one kind of record which has this set (a,b) of keys".
-> therefore you won't be able to add twice "Mario, achievement1".
Primary key will be then (PlayerID, AchievementID).
If you want to add some informations about this achievement (for example, when the player got the achievement), simply do such as: (PlayerID, AchievementID, Date) with PlayerID, AchievementID as primary key.
I hope this will help you.

Foreign key constraints and bridging tables

I am currently working with 6 tables: users, categories, videogames, videogames_categories_bridge, users_favorites, users_dislikes. I am trying to layout the tables in the best manner possible to show video games preference for user(see below example). However, I am getting a foreign key constraint error when creating the tables. How could I achieve(if possible) the below with my current tables schema? Also, Is there a way in avoiding that both values inserted(favorite and dislike) are marked true for a game? SQLFIDDLE
Example: Show all video game preference for an userid 569723
game_id category_id game_name category_name favorite dislike
------- ----------- ---------------- ------------- --------- --------
840832 1000 'counter-strike' fps 1 NULL
779343 1000 'call of duty modern warfare' fps 1 NULL
684244 2000 'minecraft' adventure NULL NULL
983565 2000 'assassin\'s creed syndicate'adventure NULL NULL
858168 3000 'need for speed - rivals' racing NULL NULL
819837 4000 'mortal kombat x' fighting NULL NULL
634266 5000 'street fighter v' fighting NULL NULL
You have some problems with your foreign keys and tables in general:
the "destination" column of the foreign key reference has to be indexed so InnoDB can quickly check if it exists etc. (for instance user_id in your users table is only a second column in your primary key, it has to be first in some index)
in one case (videogames_categories_bridge.category_id) you try to reference the same column in the same table, that does not make sense
primary keys in users and categories contain the name AND id at the same time so they do not enforce much - usually the ID is the right one for a foreign key. The way you defined it there might be the same id for multiple different names.
http://sqlfiddle.com/#!9/9e24b - the FKs modified to work

normalization - 1NF clarification

i have a question about the 1 normal form and will explain it by an example.
lets imagine that we have a set of students that are working on a set of projects, but not necessarily only one, but more than one (many to many relation). we have a table where the information's of the students are recorded, and one for the projects. but we need to link them together. but since the 1NF says redundancy and only value per tuple, how would you do it?
both fields are primary keys here
illustation 1:
student_ID project_ID
1 7
2 7,1
3 4,1,9
4 1,3
5 1
illustration 2:
student_ID project_ID
1 7
2 1
2 7
3 4
3 1
3 9
4 1
4 3
5 1
Illustration 1: I know that if this would be a result of a table, this would violate the 1NF becuase one than one value per tuple.
Ilustration 2: since they are primary keys they are not allowed to be duplicated, even if i remove the primary key from the student_ID i still would be redundant.
How can i fix this issue?
thanks in advance :)
The primary key of this table will be a composite of the two fields. They must both together be unique. Both fields are foreign keys to their respective tables and they will be unique in their respective tables.
What you have here is basically a junction table, and your second illustration shows the correct way to normalize it.
Note that, as is typical for junction tables, the primary key for your table will consist of both of the columns together. Together, each unique combination of values in these columns specifies a distinct student–project pairing.
Edit: In MySQL, you would define this table e.g. as:
CREATE TABLE student_projects (
student_id INTEGER NOT NULL,
project_id INTEGER NOT NULL,
PRIMARY KEY (student_id, project_id)
)
To enforce relational consistency, you may also want to add explicit foreign key constraints to each of the columns.

Build a field-lookup-query using the value of another field

Creating a mini-database with access, i came across this problem:
For the background, i have two tables:
Table: Items and Table: Actions
ID(PK) Name ID(PK) Name
------------------ ----------------
1 Thing1 1 Move
2 Thing2 2 Delete
3 Thing3
I created a query that lists available actions for each item:
Query: AvailableActions
Item_ID Action_ID
------------------------
1 2 //Thing1 can be deleted
2 1 //Thing2 can be moved
2 2 //Thing1 can be deleted
(no more records)
Now i want to populate a third table that lists the history of objects
Table: History
ID(PK) Item_ID Action_ID
----------------------------------
1 1 2
2 1 2
3 2 1
4 2 2
So i'm trying to make a lookup-field for Action_ID, where i can only pick values that are allowed for the choosed item. However, be it in design mode or SQL mode, i can't get the value of that field.
Do you have any hints?
Before you sort out the UI (mop the floor...), ensure you have the required constraint on the table (...fix the leak) e.g. ANSI-92 Query Mode SQL DDL:
ALTER TABLE History ADD
CONSTRAINT fk__history__AvailableActions
FOREIGN KEY (Item_ID, Action_ID)
REFERENCES AvailableActions (Item_ID, Action_ID);
...assuming you already have the required unique constraint on AvailableActions (Item_ID, Action_ID).
If you want a list of actions that can be applied to Item X then you can generate this with:
SELECT Actions.ID, Actions.Name FROM Actions INNER JOIN AvailableActions
ON Actions.ID = AvailableActions.ActionID WHERE Actions.Item_ID = X
When you talk about deleting "Thing 1", do you actually intend to delete the record from the table or does that record proxy for something else (like a disk file). If you actually delete it, you will have trouble establishing a PK / FK relationship between Items and AvailableActions if that was your intent.
Well as i stated in comments, the only way i achieved this goal is by adding a sub-form to the Items form. (unable to specify this with the structure only, as those Available_actions are computed depending on that same History table)