Let's suppose I have a table of roles, for example,
Roles
-----
ID Name
0 Salesman
1 Client
2 Manager
Let's also suppose that these roles are not mutually exclusive: that is, a person can be a salesman, a client, and a manager all at the same time.
If I have a Person table with a Role field, how am I able to reference multiple rows in the Roles table?
You introduce a new table that references both of the original tables:
CREATE TABLE PersonRoles (
PersonID int not null,
RoleID int not null,
constraint PK_PersonRoles PRIMARY KEY (PersonID,RoleID),
constraint FK_PersonRoles_Persons FOREIGN KEY (PersonID) references Person (ID),
constraint FK_PersonRoles_Roles FOREIGN KEY (RoleID) references Role (ID)
)
Assuming that the multiplicity is m:n, the above is correct. I made the assumption (not listed in your question) that more than one person can be e.g. a Salesman.
You have to create another table having (at least) two columns:
PersonId, RoleId
So you can insert (e.g.)
1, 0
1, 2
2, 1
and your Person with id=1 will be a Salesman and a Manager, while Person with id=2 will be a Client.
For this to work, you will need to make a "n-m relation". You need an extra table, eg. called "person_role", that contains foreign keys to both the other tables:
Person <===> PersonRole <===> Role
So you will have 3 tables:
Person
------------
ID
Name
etc.
Role
---------
ID
Name
PersonRole
------------
PersonID
RoleID
You also should make PersonID and RoleID into an unique composite key, to avoid any duplicates
/ Carsten
Related
I have two tables. Teacher and student. The teacher table consist with id, name, classid, studentId. In student table consist of id, name, TeacherId.
One student can have more than one teachers. And the teacherid is set as foreign key in student table. Then how can I save my student table with multiple teacherid?
If a student can have multiple teachers then you can't put the teacher ID in the student table. You need a third table that contains the combinations of student ID and teacher ID. That way, one student record can be related to multiple teachers and each teacher can be related to multiple students. A third table is how you implement a many-to-many relationship.
You can have a separate table with student and teacher mapping. So, that a single student id could be mapped with multiple teacher ids and you can also have date range or deactivation columns to change your mappings.
Relationships between entities in relational databases are commonly divided into 3 types. This is called the cardinality of the relationship:
1 to N: For example an order (1) with it's products (N). In this case the product would have the order's key.
1 to 1: For example a teacher (1) with it's contact info (1). This type of relationships might raise an eyebrown since you could put the contact's info inside the teacher's table. In this case either the contact has the teacher's key or the teacher has the contact's key (or both share the same exact key).
N to M: Like in your case, a particular teacher may have more than 1 student and each of those students might have another teachers. You can't store this relationship in 2 tables (not in a good way at least), so the solution is creating a 3rd table that links the two.
For this last case, you would have something like the following:
CREATE TABLE Teacher (
TeacherID INT PRIMARY KEY,
-- Other teacher columns
)
CREATE TABLE Student (
StudentID INT PRIMARY KEY,
-- Other student columns
)
CREATE TABLE TeacherByStudent (
TeacherID INT,
StudentID INT,
PRIMARY KEY (TeacherID, StudentID),
FOREIGN KEY (TeacherID) REFERENCES Teacher (TeacherID),
FOREIGN KEY (StudentID) REFERENCES Student (StudentID))
Better you should following tables
Student
Id (Primary Key)
Name
Teacher
Id (Primary Key)
Name
ClassId (Foreign Key)
TeacherStudentMapping
Id (Primary Key)
StudentId
TeacherId
Set Unique Key for StudentId & TeacherId.
I have two tables:
People:
Id | OrgId | Name
-----------------
1 10 Sam
2 10 Dana
3 12 Max
Id is a primary key. OrgId is foreign key to other table.
And second table Cars:
Id | Name | OrgId | PersonId
----------------------------
1 Volvo 10 1
2 BMW 10 2
Here: Id is a primary key. PersonId is a foreign key to People table. OrgId is foreign key to Organization table.
So I have Person which are attached to Organization and I have Cars which are attached to Organization and Person.
I need to guarantee that it will be impossible to attach Car from one Organization to Person from another Organization. The record:
Id | Name | OrgId | PersonId
----------------------------
1 Volvo 12 1
must be impossible because Car belongs to Organization with ID = 12, but Person belongs to Organization with ID = 10.
What is the best way to do it ?
I see two ways:
Foreign key using two fields People (Id + OrgId) <-> Cars (PersonId + OrgId).
But in this case I need to create one additional unique index on the table People ('Id+OrgId`).
Trigger on the table Cars.
What do you recommend to use in this case ?
My first reaction is to look up the organization using the person column. But, that doesn't really fit the situation -- cars are owned by organizations independently of people. So, you might need the organization, even if no person is assigned.
So, add a new key to people:
alter table people add constraint unq_people_orgid_id unique (orgid, id);
Then use this for the foreign key reference in cars:
alter table cars add constraint
foreign key (orgid, personid) references people(orgid, id);
Note that the second key is redundant. But it allows a reference that includes the organization.
I wouldn't use OrgId in your cars table, it violates normalization rules. You can use a query to get the organization information for the car using the PersonId.
I'm trying to make a simple database for a personal project, and I'm not sure whether i'm using Primary Keys properly.
Basically, the database contains users who have votes yes/no on many different items.
Example :
User "JOHN" voted YES on item_1 and item_2, but voted FALSE on item_3.
User "BOB" voted YES on item_1 and item_6.
User "PAUL" votes NO on item_55 and item_76 and item_45.
I want to use the following 3 tables (PK means Primary Key) :
1) table_users, which contains the columns "PK_userID" and "name"
2) table_items, which contains the columns "PK_itemID" and "item_name"
3) table_votes, which contains the columns "PK_userID", "PK_itemID", and "vote"
and the columns with the same name will be linked
Does it look like a proper way to use primary keys ? (so the table_votes will have two Primary Keys, being linked to the two other tables)
Thanks :)
Since user can vote for multiple items and multiple users can vote for a single item, you should not create following two primary keys in third table table_votes. Just create them as fields otherwise it will restrict you add only a userId or itemId only once. Yep, you should make them NOT NULL
"PK_userID", "PK_itemID",
No, that's not correct.
There can only be one primary key per table. You can have other columns with unique indexes that could have been candidate keys, but that's not the primary.
I think you'd have three tables:
create table PERSON (
PERSON_ID int not null identity,
primary key(PERSON_ID)
);
create table ITEM (
ITEM_ID int not null identity,
primary key(ITEM_ID)
);
create table VOTE (
PERSON_ID int,
ITEM_ID int,
primary key(PERSON_ID, ITEM_ID),
foreign key(PERSON_ID) references PERSON(PERSON_ID),
foreign key(ITEM_ID) references ITEM(ITEM_ID)
);
It's a matter of cardinality. A person can vote on many items; an item can be voted on by many persons.
select p.PERSON_ID, i.ITEM_ID, COUNT(*) as vote_count
from PERSON as p
join VOTE as v
on p.PERSON_ID = v.PERSON_ID
join ITEM as i
on i.ITEM_ID = v.PERSON_ID
group by p.PERSON_ID, i.ITEM_ID
This looks reasonable. However, I would not advise you to name your primary keys with a "PK_" prefix. This can be confusing, especially because I advise giving foreign keys and primary keys the same name (the relationship is then obvious). Instead, just name it after the table with Id as a suffix. I would recommend a table structure such as this:
create table Users (
UserId int not null auto_increment primary key,
Name varchar(255) -- Note: you probably want this to be unique
);
create table Items (
ItemId int not null auto_increment primary key,
ItemName varchar(255) -- Note: you probably want this to be unique
);
create table Votes (
UserId int not null references Users(UserId),
ItemId int not null references Items(ItemId),
Votes int,
constraint pk_UserId_ItemId primary key (UserId, ItemId)
);
Actually, I would be inclined to have an auto-incremented primary key in Votes, with UserId, ItemId declared as unique. However, there are good arguments for doing this either way, so that is more a matter of preference.
I'm working on an application which has different types of users i.e. students, tutors, and administrators. However, I initially set up my database to have only two tables: Users (that holds all the login information, common to all types) and Profiles (that holds all other information; though each column applies to a certain type of user).
I was thinking maybe I should have Users, and 3 separate tables for each type i.e. Students, Tutors, and Administrators. However, how do I link those three tables with Users table? I'm sure there would be a bridge table but I'm not too sure how to do that.
This should be a solid starting point for you. Define the tables which it sounds like you are ok with, then apply the relationships using the ALTER TABLE command. See below.
CREATE TABLE Users
(
ID INT IDENTITY (1,1),
PRIMARY KEY (ID),
UserName VARCHAR(20),
Password VARCHAR(20)
)
CREATE TABLE Students
(
ID INT IDENTITY (1,1),
PRIMARY KEY (ID),
UserID INT --foreign key to Users.ID column
--Other columns
)
CREATE TABLE Tutors
(
ID INT IDENTITY (1,1),
PRIMARY KEY (ID),
UserID INT --foreign key to Users.ID column
--Other columns
)
CREATE TABLE Administrators
(
ID INT IDENTITY (1,1),
PRIMARY KEY (ID),
UserID INT --foreign key to Users.ID column
--Other columns
)
--Apply foreign key relationships
ALTER TABLE Students
ADD FOREIGN KEY (UserID)
REFERENCES Users(ID)
ALTER TABLE Tutors
ADD FOREIGN KEY (UserID)
REFERENCES Users(ID)
ALTER TABLE Administrators
ADD FOREIGN KEY (UserID)
REFERENCES Users(ID)
You would add the primary key of the Users table as a foreign key to each of the 3 seperate tables.
Hope this helps.
USER_TYPE table, containing userType and userTypeID columns.
USER table, containing userID column plus login information, plus a userTypeID column, linking to USER_TYPE table.
USER_STUDENT table, containing student related columns, plus a userID column, linking to the USER table.
USER_TUTOR table, containing tutor related columns, plus a userID column, linking to the USER table.
USER_ADMINISTRATOR table, containing administrator related columns, plus a userID column, linking to the USER table.
You can JOIN 1, 2 and {3 or 4 or 5} tables as shown below, and in similar other ways:
SELECT U.*, S.*
FROM USER as U
INNER JOIN USER_TYPE AS UT ON UT.userTypeID = U.userTypeID
INNER JOIN USER_STUDENT AS US ON US.userID = U.userID
WHERE UT.userType = 'STUDENT'
Another approach is to introduce a "role" table that defines the type of roles/profiles in your system (student, admin, tutor, ...), then add a mapping table "user_role" which maps users to roles (ie John is both a student and a teacher implies two records in the "user_role" table. Role-specific information for a user can be in the tables shown as "detail" tables below.
USER
----
user_id
username
password
ROLE
----
role_id
role_name
USER_ROLE
----------
user_role_id
user_id
role_id
from_date
to_date
STUDENT_DETAIL
--------------
user_role_id
student_number
TUTOR_DETAIL
------------
user_role_id
sin
What is the best way of handling many-to-many relations in a RDBMS database like mySQL?
Have tried using a pivot table to keep track of the relationships, but it leads to either one of the following:
Normalization gets left behind
Columns that is empty or null
What approach have you taken in order to support many-to-many relationships?
Keep track of a many-to-many relationship in a table specifically for that relationship (sometimes called a junction table). This table models the relationship as two one-to-many relationships pointing in opposite directions.
CREATE TABLE customer (
customer_id VARCHAR NOT NULL,
name VARCHAR NOT NULL,
PRIMARY KEY (customer_id));
CREATE TABLE publication (
issn VARCHAR NOT NULL,
name VARCHAR NOT NULL,
PRIMARY KEY (issn));
-- Many-to-many relationship for subscriptions.
CREATE TABLE subscription (
customer_id VARCHAR NOT NULL,
FOREIGN KEY customer_id REFERENCES customer (customer_id),
issn VARCHAR NOT NULL,
FOREIGN KEY issn REFERENCES publication (issn),
begin TIMESTAMP NOT NULL,
PRIMARY KEY (customer_id, issn));
You then use the junction table to join other tables through it via the foreign keys.
-- Which customers subscribe to publications named 'Your Garden Gnome'?
SELECT customer.*
FROM customer
JOIN subscription
ON subscription.customer_id = customer.customer_id
JOIN publication
ON subscription.issn = publication.issn
WHERE
publication.name = 'Your Garden Gnome';
-- Which publications do customers named 'Fred Nurk' subscribe to?
SELECT publication.*
FROM publication
JOIN subscription
ON subscription.issn = publication.issn
JOIN customer
ON subscription.customer_id = customer.customer_id
WHERE
customer.name = 'Fred Nurk';
I would use a pivot table, but I don't see where your issues are coming from. Using a simple student/class example:
Student
-------
Id (Primary Key)
FirstName
LastName
Course
------
Id (Primary Key)
Title
StudentCourse
-------------
StudentId (Foreign Key -> Student)
CourseId (Foreign Key -> Course)
Or, as somebody else mentioned in response to your Student/Teacher/Course question (which would have an additional table to store the type of person in the course):
PersonType
----------
Id (Primary Key)
Type
Person
------
Id (Primary Key)
FirstName
LastName
Type (Foreign Key -> PersonType)
Course
------
Id (Primary Key)
Title
PersonCourse
------------
PersonId (Foreign Key -> Person)
CourseId (Foreign Key -> Course)
The Student table contains student information, the Course table stores course information...and the pivot table simply contains the Ids of the relevant students and courses. That shouldn't lead to any null/empty columns or anything.
In addition to Justin's answer: if you make clever use of Foreign Key constraints, you can control what happens when data gets updated or deleted. That way, you can make sure that you do not end up with de-normalized data.