I'm currently designing a database structure for our team's project. I have this very question in mind currently: Is it possible to have a foreign key act as a primary key on another table?
Here are some of the tables of our system's database design:
user_accounts
students
guidance_counselors
What I wanted to happen is that the user_accounts table should contain the IDs (supposedly the login credential to the system) and passwords of both the student users and guidance counselor users. In short, the primary keys of both the students and guidance_counselors table are also the foreign key from the user_accounts table. But I am not sure if it is allowed.
Another question is: a student_rec table also exists, which requires a student_number (which is the user_id in the user_accounts table) and a guidance_counsellor_id (which is also the user_id in the user_accounts) for each of its record. If both the IDs of a student and guidance counselor come from the user_accounts table, how would I design the student_rec table? And for future reference, how do I manually write it as an SQL code?
This has been bugging me and I can't find any specific or sure answer to my questions.
Of course. This is a common technique known as supertyping tables. As in your example, the idea is that one table contains a superset of entities and has common attributes describing a general entity, and other tables contain subsets of those entities with specific attributes. It's not unlike a simple class hierarchy in object-oriented design.
For your second question, one table can have two columns which are separately foreign keys to the same other table. When the database builds the query, it joins that other table twice. To illustrate in a SQL query (not sure about MySQL syntax, I haven't used it in a long time, so this is MS SQL syntax specifically), you would give that table two distinct aliases when selecting data. Something like this:
SELECT
student_accounts.name AS student_name,
counselor_accounts.name AS counselor_name
FROM
student_rec
INNER JOIN user_accounts AS student_accounts
ON student_rec.student_number = student_accounts.user_id
INNER JOIN user_accounts AS counselor_accounts
ON student_rec.guidance_counselor_id = counselor_accounts.user_id
This essentially takes the student_rec table and combines it with the user_accounts table twice, once on each column, and assigns two different aliases when combining them so as to tell them apart.
Yes, there should be no problem. Foreign keys and primary keys are orthogonal to each other, it's fine for a column or a set of columns to be both the primary key for that table (which requires them to be unique) and also to be associated with a primary key / unique constraint in another table.
Related
i have entity customer and entity order, a customer can have 0 or more orders but an order can only have 1 customer.
I already tried a lot of things like making the foreign key unchecked at NN but I cant get a foreign key order at customer
EDIT: Using mySQL ERD workbench
Your customer table will have a unique customer_id column. In the MySQL world we often use autoincrementing primary keys for this kind of id column.
Your order table will have a customer_id column that's a foreign key to customer.customer_id.
This allows the order table to have any number of rows relating to a particular customer_id: none, one, or many. The foreign key relationship, when enforced--checked--simply prevents an order from having a customer_id value that references no valid customer.
Classic data design tools with their distinction between logical and physical design can drive ya nuts when you're trying to do easy stuff like this.
Pro tip if you name your id columns the same way everywhere they're used, data design tools tend to work better, especially when "reverse-engineering" your tables. That's why I suggested column names like customer.customer_id and order.customer_id rather than customer.id and order.customer_id.
I have one table
program(p_id(pk), program_name)
and three other tables:
graduate_survey(id(pk),PO1_avg,PO2_avg,program_name,session),
alumni_survey(id(pk),PO1_avg,PO2_avg,program_name,session),
faculty_survey(id(pk),PO1_avg,PO2_avg,program_name,session)...
I have to link the three tables with program table...How to link these tables in MySQL? graduate_survey, alumni_survey, faculty_survey are some forms which is calculated for some specific program...If in the forms graduate_survey, alumni_survey, faculty_survey there is no text box for entering the program_name, but if i made a column name 'program_name' in the database tables, can i enter the program_name by referencing to the program table? Is there will be any join query?
Use the program id as foreign key in the other tables, like so:
program(p_id(pk), program_name)
graduate_survey(id(pk),PO1_avg,PO2_avg,p_id(fk),session),
alumni_survey(id(pk),PO1_avg,PO2_avg,p_id(fk),session),
faculty_survey(id(pk),PO1_avg,PO2_avg,p_id(fk),session)
You don't really need the program name for the sake of the FK constraints but it's still a nice to have at some point, maybe.
This way you can easily join based on p_id, for instance:
"SELECT * FROM program INNER JOIN graduate_survey ON program.p_id=graduate_survey.p_id WHERE <your condition here>"
Hope this helps.
I have a question regarding foreign keys. I have searched for the answer and was unable to location one.
I have a table 'projects' that has the column 'owner_id' which references 'managers.owner_id' as a foreign key.
Would it be possible to reference 'managers.owner_id' as a foreign key, but show the column 'managers.full_name'? When I run a SELECT query against the 'projects' table, I want to see the manager's name to come up and not the manager's id.
If it is possible, is this normally done with the SELECT command or can I configure it when I CREATE/ALTER the 'projects' table?
I am fairly new with MySQL, thank you for your time and patience!
If what I'm asking seems insane, I wouldn't mind hearing what your thoughts are or if you have any other suggestions.
You just need to join the tables and select the fields that you want e.g.
SELECT projects.project_name, managers.full_name
FROM projects
INNER JOIN managers on projects.owner_id = managers.owner_id
If there are projects where the owner_id is NULL but you still want to list it then use a LEFT JOIN instead.
Is there any sense in using two foreign key to the same parent table, to avoid inner join?
table: user_profile
id1, userid, username, firstname
table: user_hobby1
id2, userid(fk), hobby, movies
table: user_hobby2
id3, userid(fk), firstname(fk), hobby, movies
I want to select all firstname and hobby from the above table. I am not sure if user_hobby1 or user_hobby2 is the best design in terms of performance? One adds extra foreign key and another requires join.
Query1 :
Select firstname, hobby
from user_hobby2;
Query2 :
Select p.firstname, h.hobby
from
user_profile p
inner join user_hobby1 h on u.userid=h.userid;
Copying the value of an attribute from the user table into the hobby table isn't a "foreign key", that's redundancy.
Our performance objectives are not usually met with an approach of avoiding JOIN operations, which are a normal part of how relational databases operate.
I'd go with the normalized design as a first cut. Each attribute should be dependent on the key, the whole key, and nothing but the key. The "firstname" attribute is dependent on the id of the user, not the hobby.
Sometimes, we do gain performance benefits by introducing redundancy into the database. We have to do that in a controlled way, and make sure that we don't get update anomalies. (Consider what changes we want to apply if the value of "firstname" attribute is updated... do we make that change to the user table, the user_hobby table, or both.
Likely, "firstname" is not unique in the user table, so we definitely don't want a foreign key referencing that column; we want foreign keys that reference the user table to reference the PRIMARY KEY of the table.
There's no point in having two foreign keys defined between user_hobby and user, if a user_hobby is related to exactly one user. We only need one foreign key... we just store the id from the user table in the user_hobby table.
if you have two FK in user_hobby2 then you can only ensure that userid and username exist in user_profile, but you have no way to ensure which userid goes with a given username.
if you make (userid, username) a composite FK, then you'll guarantee the consistency of each tuple, but composite FK are generally more complicate to deal with. Depending on the behavior for update and delete cascades I've seen mysql triggering them both and refusing to delete from the parent.
Besides... what's the point of keeping that composite FK? It will only help you when you update or delete from user_profile, but won't help you copy the data when you insert new users or new hobbies for a user.
The join you are trying to avoid is very cheap. Just go with the first approach. It's easier to maintain and will help you keep your data consistent and normalized.
Been reading the tutorial How to handle a Many-to-Many relationship with PHP and MySQL .
In this question I refer to the "Database schema" section which states the following rules:
This new table must be constructed to
allow the following:
* It must have a column which links back to table 'A'.
* It must have a column which links back to table 'B'.
* It must allow no more than one row to exist for any combination of rows from table 'A' and table 'B'.
* It must have a primary key.
Now it's crystal clear so far.
The only problem I'm having is with the 3rd rule ("It must allow no more than one row to exist for any combination").
I want this to be applied as well, but it doesn't seem to work this way.
On my test instance of mysql (5.XX) I'm able to add two rows which reflect the same relationship!
For example, if I make this relation (by adding a row):
A to B
It also allows me to make this relation as well:
B to A
So the question is two questions actually:
1) How do I enfore the 3rd rule which will not allow to do the above? Have only one unique relation regardless of the combination.
2) When I'll want to search for all the relations of 'A', how would the SQL query look like?
Note #1: Basically my final goal is to create a "friendship" system, and as far as I understand the solution is a many-to-many table. Suggest otherwise if possible.
Note #2: The users table is on a different database from the relations (call it friendships) table. Therefore I cannot use foreign keys.
For the first question:
Create a unique constraint on both
columns
Make sure you always sort the columns. So if your table has the
colummns a and b than make sure
that a is less than or equal to
b
For the second question:
SELECT
*
FROM
many_to_many_table
WHERE
a = A or b = A
It sounds like you want a composite primary key.
CREATE TABLE relationship (
A_id INTEGER UNSIGNED NOT NULL,
B_id INTEGER UNSIGNED NOT NULL,
PRIMARY KEY (A_id, B_id)
);
This is how you setup a table so that there can only ever be one row that defines tables A and B as related. It works because a primary key has to be unique in a table so therefore the database will allow only one row with any specific pair of values. You can create composite keys that aren't a primary key and they don't have to be unique (but you can create a unique non-primary key, composite or not), but your specification requested a primary key, so that's what I suggested.
You can, of course, add other columns to store information about this specific relationship.
Ok WoLpH was faster, I basically agree (note that you have to create a single constraint on both columns at the same time!). And just to explain why you collide with the rules you mentioned: Typically, A and B are different tables. So the typical example for n:m relations would allow entries (1,0) and (0,1) because they'd be refering to different pairs. Having table A=table B is a different situation (you use A and B as users, but in the example they're tables).