Many-to-many relations in RDBMS databases - sql

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.

Related

How can i save multiple foriegn key value in my table?

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.

How do I ensure integrity between unrelated tables?

I just recently started learning database design, and I'm am working with Oracle 11G and SQL Developer.
I have these 3 business rules for a DB:
Each OFFICER must enroll in one and only one INSURANCE COMPANIES. each INSURANCE COMPANY may enroll one or more OFFICERS
Each INSURANCE COMPANY must provide at least five different types of INSURANCE TYPES. Each TYPE OF INSURANCE may be provided by up to 4 INSURANCE COMPANIES or none at all
Each INSURANCE TYPE may be subscribed to by one or more OFFICERS. Each OFFICER may subscribe to up to FIVE different INSURANCE COVERS provided by the same company.
.
.
.
so far, so good, i came up with five TABLES (INS_COY, OFFR, INS_TYPE, PROVIDE, and SUBSCRIBE). PROVIDE and SUBSCRIBE came about as composite tables since the relationships between INS_COY and INS_TYPE, and OFFR and INS_TYPE are both M:M relationships.
PK and FK attributes for each of the table is as below:
INS_COY TABLE
coy_id - PK
OFFR TABLE
offr_id - PK
coy_id - (FK referencing INS_COY.coy_id))
INS_TYPE TABLE
type_id - PK
PROVIDE
coy_id and type_id - (composite PK)
coy_id - (FK referencing COY.coy_id)
type_id - (FK referencing ins_type.type_id)
SUBSCRIBE
naf_no and type_id - (composite PK)
naf_no - (FK referencing offr.offr_id)
type_id (FK referencing ins_type.type_id)
.
.
.
the tables have been sucessfully created, and sample data inserted.
so, the problem is - on the SUBSCRIBE TABLE, HOW DO I ENSURE INTEGRITY THAT THE TYPE_ID ATTACHED TO AN OFFR_ID IS AN INS_TYPE PROVIDED BY THE COY HE IS ENROLLED IN?
sample data tables
i.e ...from the tables, "offr 4250" is enrolled in "coy 1", and "coy 1" doesn't provide "ins_type 13", however, because there's no constraint to check this, "offr 1" is subscribed to "ins_type 13" on the SUBSCRIBE TABLE.
You can do it using controlled redundancy and composite FK constraints:
CREATE TABLE offr (
offr_id INT NOT NULL,
coy_id INT NOT NULL,
PRIMARY KEY (offr_id),
FOREIGN KEY (coy_id) REFERENCES ins_coy (coy_id),
UNIQUE KEY (offr_id, coy_id)
);
I added a composite unique key (offr_id, coy_id) to support a composite FK constraint on the subscribe table.
CREATE TABLE provide (
coy_id INT NOT NULL,
type_id INT NOT NULL,
PRIMARY KEY (coy_id, type_id),
FOREIGN KEY (coy_id) REFERENCES ins_coy (coy_id)
);
The composite primary key here is perfect for a composite FK constraint on the subscribe table.
CREATE TABLE subscribe (
naf_no INT NOT NULL,
coy_id INT NOT NULL,
type_id INT NOT NULL,
PRIMARY KEY (naf_no, type_id),
FOREIGN KEY (naf_no, coy_id) REFERENCES offr (offr_id, coy_id),
FOREIGN KEY (coy_id, type_id) REFERENCES provide (coy_id, type_id)
);
Overlapping composite FK constraints will ensure that an officer can only subscribe to insurance offered by the company he/she is enrolled in. coy_id is logically redundant but required for integrity and there's no risk of update anomalies due to the FK constraints.
Alternatively, you could use triggers to check that the values are related via inner joins:
CREATE TRIGGER check_subscribe BEFORE INSERT OR UPDATE ON subscribe
FOR EACH ROW
WHEN NOT EXISTS (
SELECT 1
FROM offr
INNER JOIN provide ON offr.coy_id = provide.coy_id
WHERE offr.offr_id = new.naf_no AND provide.type_id = new.type_id
)
RAISE_APPLICATION_ERROR (num => -20000, msg => 'Officers can only subscribe to types provided by their company');
Disclaimer: I was unable to test this on SqlFiddle and don't have Oracle installed, but hopefully it'll point you in the right direction.

query with SQL m:n relationships

I have a quick question with respect to many to many relationships in sql.
So theoretically i understand that if 2 entities in an ER model have a M:N relationship between them, we have to split that into 2 1:N relationships with the inclusion of an intersection/lookup table which has a composite primary key from both the parent tables. But, my question here is , in addition to the composite primary key, can there be any other extra column added to the composite table which are not in any of the 2 parent tables ? (apart from intersectionTableId, table1ID, table2ID) a 4rth column which is entirely new and not in any of the 2 parent tables ? Please let me know.
In a word - yes. It's a common practice to denote properties of the relationship between the two entities.
E.g., consider you have a database storing the details of people and the sports teams they like:
CREATE TABLE person (
id INT PRIMARY KEY,
first_name VARCHAR(10),
last_name VARCHAR(10)
);
CREATE TABLE team (
id INT PRIMARY KEY,
name VARCHAR(10)
);
A person may like more than one team, which is your classic M:N relationship table. But, you could also add some details to this entity, such as when did a person start liking a team:
CREATE TABLE fandom (
person_id INT NOT NULL REFERENCES person(id),
team_id INT NOT NULL REFERENCES team(id),
fandom_started DATE,
PRIMARY KEY (person_id, team_id)
);
Yes, you can do that by modeling the "relationship" table yourself explicitly (just like your other entities).
Here are some posts about exactly that question.
Create code first, many to many, with additional fields in association table
Entity Framework CodeFirst many to many relationship with additional information

One-to-many SQL relationship on keys with different types

For example, how can I create a one-to-many relationship between tables InsuranceCo and Vehicle, where the primary keys of each are InsuranceCo.id and Vehicle.licencePlate?
My attempt in creating the one-to-many relationship using a foreign key is this:
CREATE TABLE InsuranceCo (
id int PRIMARY KEY,
phone int
)
CREATE TABLE Vehicle (
licencePlate CHAR(10) PRIMARY KEY REFERENCES InsuranceCo(id),
year int
)
Will this work? If not, how can I create the one-to-many relationship when keys have different types?
This isn't how one-to-many relationships work at all. You don't just link two ids together, that is how one-to-one relations work (and no, those can't be done with different types, the values actually have to be the same). For one-to-many relationships, you need a separate value to reference the other table with.
You have to add a column -- for example insuranceCoId -- into the Vehicle table. Then any vehicle can have the id of the insurance company right there in the table. So data in might look like this:
InsuranceCo:
id phone
1 800-744-2932
2 488-382-9332
Vehicle
LicencePlate insuranceCoId year
435yte 1 1995
328teo 1 2006
fd8tew 2 2008
As you can see, one insurance company is associated with many vehicles now.
I'm assuming that in the one-to-many relationship, InsuranceCo will have a multiplicity of 1 and Vehicle will have a multiplicity of * (many).
In this case, you'll want to create an additional column on the Vehicle table of type int called InsuranceCoId, which will be a foreign key reference to the InsuranceCo table. You can then create said foreign key constraint on the Vehicle table itself:
ALTER TABLE Vehicle
ADD CONSTRAINT FK_Vehicle_InsuranceCo
FOREIGN KEY (InsuranceCoId)
REFERENCES InsuranceCo (id)
Now, when you add vehicles to the system, you can add associated insurance company references.
The above will address the immediate question you have.
However, I believe your database design could be improved by adding an InsurancePolicy table that will create a many-to-many relationship between Vehicle and InsuranceCo, tied together with information specific to a policy (such as premium, deductible, etc).
You can not have a one-to-many relationship with keys of different types. This is an example of poor database design. The licencePlate should not be a primary key or foreign key in that table. What will happen when someone renew their license plate and some records in other tables are related to the old one? You should change your design to something like this:
CREATE TABLE Vehicle (
vehicleId int PRIMARY KEY,
insuranceId int,
licencePlate CHAR(10),
year int,
FOREIGN KEY (insuranceId) REFERENCES InsuranceCo(Id)
)
Make sure your primary keys are auto-incremented (or your application is handling them correctly). Use the insuranceId for the one to many relationship to InsuranceCo...
I am considering having a many to many relationship for most(if not all) entities in my organisation.
Using your example:
CREATE TABLE InsuranceCo (
Id int PRIMARY KEY,
Phone int
)
CREATE TABLE Vehicle (
Id int PRIMARY KEY,
LicencePlate CHAR(10),
Year int
)
CREATE TABLE VehiclesInInsuranceCo (
Id int,
VehicleId FOREIGN KEY REFERENCES Vehicle(Id),
InsuranceCoId FOREIGN KEY REFERENCES InsuranceCo(Id)
)
If you are following you can see InsuranceCo and Vehicle exist completely independently of each other and can be populated by some automated script.
When you want to connect a vehicle to an insurance company, you would do this:
InsuranceCo
Id 1, Phone 07944555554
Id 2, Phone 07944555557
Vehicle
Id 1, LicensePlate K1NGS, Year 2016
Id 2, LicensePlate S0L1D, Year 2015
VehiclesInInsuranceCo
Id 1, VehicleId 1, InsuranceCoId 1
Id 2, VehicleId 2, InsuranceCoId 1
So from the dataset, we can see that there are 2 vehicles in insurance company 1 and no vehicles in insurance company 2.
If there are any possible problems in using this pattern, please let me know as in my mind, this solves regularly occurring problems in databases when tables become unmanageable because they have columns that were added later ad-hoc without much consideration of the null rows that will exist.

valid schema for company and suppliers and clients?

I am having a problem in modeling relation between a company and suppliers and clients. Basically in my system the supplier and the client are companies too so I made this schema:
table.company:
id
name
//other fields
table.company_suppliers:
company_id FK table.company.id
supplier_id FK table.company.id
table.company_clients:
company_id FK table.company.id
client_id FK table.company.id
Is this ok?
I would use only one table which will contains all the company and a bit field (called by instance Supplier )which will tell you which are are suppliers too.
Company
Id
Name
IsSupplier (bit)
Fk_IdSupplier --it will relate this supplier to a company on the same table
Or you can create a junction table (many to many)
Company
Id
Name
IsSupplier (bit)
CompanySupplier
fk_IdCompany
fk_IdSupplier
Your basic insight is right--you don't want unrelated tables of clients and suppliers. But you have too many ID numbers.
create table companies (
company_id integer primary key,
company_name varchar(35) not null
);
create table suppliers (
supplier_id integer primary key references companies (company_id)
-- Other supplier columns go here.
);
create table clients (
client_id integer primary key references companies (company_id)
-- Other client columns go here.
);
If you're using MySQL, you'll need to adjust the syntax a little. MySQL doesn't support all the standard SQL syntax for declaring primary keys and foreign keys.