I learned about many-to-many relationships in College, and I never really understood them. So far I've been working with one-to-many relationships which are easy to understand and deal with.
Can somebody please give a practical example of a many-to-many relationship, and explain why we need a bridging table for it. Plus, do you need a bridging table for a one-to-many relationship as well? As far as I understand you don't need a bridging table for it, but a friend of mine recently told me otherwise.
One-to-many & many-to-many relationships are not the property of the data rather the relationship itself. And yes you do need bridging/third table for many-to-many relationship in perfect normalized RDBMS world. Lets see each of it with real life example:
One-to-many relationship: When one row of table A can be linked to one or more rows of table B.
Real Life Example: A car manufacturer makes multiple models of the cars, but a same car model can't be manufactured by two manufacturers.
Data Model:
Many-to-many relationship: When one row of table A can be linked to one or more rows of table B, and vice-versa.
Real Life Example: A user can belong to multiple community, and a community can have multiple users.
Data Model:
A practical example to many-to-many is the courses taken in a college. You might have a Courses table like:
CourseId | CourseName
=====================
1 | Algebra 101
2 | Intro to Calculus
3 | Advanced C++
4 | Go Programming
...
And there are Students:
StudentId | Name
===========================
1 | John Doe
2 | Frank Smith
3 | Mary Brown
...
Now, if you think of it, a Student can take multiple (many) Courses and a Course can have many attendant Students. That constitutes a Students(many)-to-(many)Courses relation. There is no way to directly express this without a bridge table (I am lying here but accept there is not), so you create intermediate 3rd table:
Students_Courses
StudentID | CourseID
====================
1 | 1
1 | 3
2 | 2
2 | 4
2 | 1
3 | 2
3 | 4
We are saying:
John Doe (1) is taking (Algebra 101 and Advanced C++),
Frank Smith (2) is taking (Algebra 101, Intro to Calculus and Go Programming)
Mary Brown (3) is taking (Intro to Calculus and Go Programming)
This is like 1-To-Many looking from Students' perspective. We can also look from Courses' perspective:
Algebra 101 members are (John Doe and Frank Smith)
Intro to Calculus members (Frank Smith and Mary Brown)
Advance C++ members (John Doe)
Go Programming (Frank Smith and Mary Brown)
making another 1-To-Many from the other side.
IOW it looks like:
Student +-< Courses and Students >-+ Course
Courses >-< Students
A Many-to-Many bridging table doesn't need to only have IDs from two tables. It is what you need at least but may have other columns if you need like:
StudentId | CourseID | RegistrationDate | CompletionScore
=========================================================
1 | 1 | 2017/02/15 | A+
1 | 3 | 2017/04/07 | NULL
And 1-To-Many tables DO NOT have a bridging table. A typical example is Customers and Orders. A Customer can have (many) Orders but an Order belongs to a single (one) Customer. Orders table itself directly has a foreign key (CustomerId) pointing to its belonging Customer so there is no bridge table.
Note: These are in context of the traditional RDBMS. A many-to-many might be expressed without a bridging table but at this point I would assume that as advanced topic.
This question is old, but a practical example would be found in social networks like Instagram:
You (the follower) follow a person A (the followee).
You also follow person B, person C, etc..., but you are not the only one who may follow person A, as well as not the only one who may follow person B, person C, etc... Your friend or other people may as well follow them too.
So you end up with data shaped in the following way:
Follower | Followee
--------------|--------------
... | ...
You | A
You | B
You | C
Your friend | A
Your friend | B
Your friend | C
... | ...
Which is what you call a bridging table (aka lookup table), describing a many-to-many relationship.
Continuing with the social network example, you need a many-to-many bridging/lookup table otherwise you would have to introduce redundancy in your users table, because you would need to duplicate your You record and that of your friend (Your friend) for each of your followees (A, B, C), which is of course non-practical and violates normalization.
do you need a bridging table for a one to many relationships as well ? As far as I understand you don't need a bridging table for a one to many relationship, but a friend of mine recently told me otherwise.
You may use a bridging/lookup table for a one-to-many relationship for flexibility purposes when e.g. you don't know in advance if the relationship of your data is effectively many-to-many or the relationship is one-to-many but you think that it can evolve and become many-to-many in the future.
Related
I have a question about proper table design. Imagine the situation:
You have two entities in the table (Company and Actor).
Actor could have several types (i.e. Shop, PoS, Individual etc.)
The relation between entities is many-to-many because one Actor can be assigned to multiple Companies and vice-versa (one Company can have multiple Actors)
To outline this relation, I can create a linking table called 'C2A' for instance. So, we'll end up with the structure like this:
| Company1 | Actor1(Shop)
| Company1 | Actor2(PoS)
| Company2 | Actor1(PoS)
etc.
This approach works just fine until requirement changes. Now we need to have a possibility to assign Actor to an Actor to build another sort of hierarchy, i.e. one Actor (Shop) might have multiple other Actors (PoS's) assigned to it and all this belong to a certain company. So, we'll end up with the structure like this:
| Company1 | Actor1(Shop) | NULL
| NULL | Actor1(Shop) | Actor1(PoS)
| NULL | Actor1(Shop) | Actor2(PoS)
etc.
I need to be able to express relations (between Company (C) and Actor(A)) like this: C - A - A; A - C - A; A - A - C
Having two similar fields in one table is not the best idea. How are the relationships like this normally designed?
Create two separate tables for entities Company and Actors.
Company( Id (PK), Name)
Actor(Id (PK), Name)
Now, if you are sure about many-many. You can go ahead with creating a separate table for this.
CompanyActorMap( MapId (PK), CompanyId (FK), ActorId (FK))
For Actor Heirarchy, use a separate table as it has nothing to do with how the hierarchy is related to the company, its about how the Actors are related to each other. Best approach for multiple level infinite hierarchy is to create a new table with two columns for Actor Id as Foreign Key
ActorHierarchy( HierarchyId (PK), ChildActorId (FK), ParentActorId(FK))
For an Actor that has no parent in hierarchy, there can be an entry in CompanyActorMap table denoting the head of hierarchy and the remaining chain can be derived from the ActorHierarchy table by checking the PArentActorId column and its childActorId.
This is obviously a rough draft. Hope this helps.
I am learning to program with SQL and have just been introduced to self-joins. I understand how these work, but I don't understand what their purpose is besides a very specific usage, joining an employee table to itself to neatly display employees and their respective managers.
This usage can be demonstrated with the following table:
EmployeeID | Name | ManagerID
------ | ------------- | ------
1 | Sam | 10
2 | Harry | 4
4 | Manager | NULL
10 | AnotherManager| NULL
And the following query:
select worker.employeeID, worker.name, worker.managerID, manager.name
from employee worker join employee manager
on (worker.managerID = manager.employeeID);
Which would return:
Sam AnotherManager
Harry Manager
Besides this, are there any other circumstances where a self-join would be useful? I can't figure out a scenario where a self-join would need to be performed.
Your example is a good one. Self-joins are useful whenever a table contains a foreign key into itself. An employee has a manager, and the manager is... another employee. So a self-join makes sense there.
Many hierarchies and relationship trees are a good fit for this. For example, you might have a parent organization divided into regions, groups, teams, and offices. Each of those could be stored as an "organization", with a parent id as a column.
Or maybe your business has a referral program, and you want to record which customer referred someone. They are both 'customers', in the same table, but one has a FK link to another one.
Hierarchies that are not a good fit for this would be ones where an entity might have more than one "parent" link. For example, suppose you had facebook-style data recording every user and friendship links to other users. That could be made to fit in this model, but then you'd need a new "user" row for every friend that a user had, and every row would be a duplicate except for the "relationshipUserID" column or whatever you called it.
In many-to-many relationships, you would probably have a separate "relationship" table, with a "from" and "to" column, and perhaps a column indicating the relationship type.
I found self joins most useful in situations like this:
Get all employees that work for the same manager as Sam. (This does not have to be hierarchical, this can also be: Get all employees that work at the same location as Sam)
select e2.employeeID, e2.name
from employee e1 join employee e2
on (e1.managerID = e2.managerID)
where e1.name = 'Sam'
Also useful to find duplicates in a table, but this can be very inefficient.
There are several great examples of using self-joins here. The one I often use relates to "timetables". I work with timetables in education, but they are relevant in other cases too.
I use self-joins to work out whether two items clash with one another, e.g. a student is scheduled for two lessons which happen at the same time, or a room is double booked. For example:
CREATE TABLE StudentEvents(
StudentId int,
EventId int,
EventDate date,
StartTime time,
EndTime time
)
SELECT
se1.StudentId,
se1.EventDate,
se1.EventId Event1Id,
se1.StartTime as Event1Start,
se1.EndTime as Event1End,
se2.StartTime as Event2Start,
se2.EndTime as Event2End,
FROM
StudentEvents se1
JOIN StudentEvents se2 ON
se1.StudentId = se2.StudentId
AND se1.EventDate = se2.EventDate
AND se1.EventId > se2.EventId
--The above line prevents (a) an event being seen as clashing with itself
--and (b) the same pair of events being returned twice, once as (A,B) and once as (B,A)
WHERE
se1.StartTime < se2.EndTime AND
se1.EndTime > se2.StartTime
Similar logic can be used to find other things in "timetable data", such as a pair of trains it is possible to take from A via B to C.
Self joins are useful whenever you want to compare records of the same table against each other. Examples are: Find duplicate addresses, find customers where the delivery address is not the same as the invoice address, compare a total in a daily report (saved as record) with the total of the previous day etc.
I'm learning about entity relation diagrams (ER) and have a question regarding this. Say I had the following situation "A student can take multiple classes, but doesn't necessarily have to take any".
I'd have a set "student" (S) and a set "classes" (C). Say I want to define a relation "takes". I assume the relation "takes" would be many-to-many with partial participation. That is because a student can take multiple classes, and a class can be taken by multiple people. "Partial" because it could be that there are students who take no classes, and classes who are taken by no student. Is that correct?
Now, assuming I had a set "people" (p) and wanted to define the relation "isChildOfMother". I believe this is many-to-one? Because multiple people can have the same mother, but not multiple mothers, and one mother can have multiple children? But in this case, the relation would be pointing from set p to set p? How can I ensure it's read the right way? (Ie: Not in terms of one child can have multiple mothers but one mother can only have one child?")
I suppose the alternative would be creating a set "children" and a set "mothers", but what if somebody was a mother AND a child?
You can have a self-relationship or recursive relationship
In this case
Each person can have only one mother or no mother.
Ana doesnt have mother (orphan) or the mother isn't on the db.
Ana can have more than one children
Alice is mother and child
Person
id | name | mother_id |
1 | Ana | null
2 | Luis | 1
3 | Alice | 1
4 | Jhon | 3
For this you say mother_id is FK to Person(id)
I have an n to m relationship between authors and books. There are two possibilities I am considering for modelling this.
The first possibility is an explicit n to m relationship.
Table Author
ID Name
1 Follett
2 Rowling
3 Martin
Table Books
ID Title Category Logic Time
1 A Dance with Dragons Fantasy 1
2 Harry Potter Fantasy 3
3 The Key to Rebecca Thriller 2
4 World without end Drama 4
Table book_author
authorId bookId
1 3
2 2
3 1
1 4
The second possibility is to store the author id in the book. EDIT If there are several authors per book I would have to enter the book once for each author.
Table Author
ID Name
1 Follett
2 Rowling
3 Martin
Table Books
ID Title Category Logic Time AuthorId
1 A Dance with Dragons Fantasy 1 3
2 Harry Potter Fantasy 3 2
3 The Key to Rebecca Thriller 2 1
4 World without end Drama 4 1
Assume I want to find out for a specific author (Ken Follett with id 1) the first book he published.
In the first case the query would look like:
select * from books b join
book_author ba on b.id = ba.book_id
where ba.author_id = 1
order by b.logic_time asc;
In the second case the query would look like:
select * from books b
where a.author_id = 1
order by b.logic_time asc;
I am storing the ids of authors in the overlying system to avoid further joins with the author table. I am never interested in the details of authors. It is expected that there are a lot more books in the system than authors.
I am tending towards the first option since it is "cleaner" (EDIT: no duplicate book entries necessary), but I am having some troubles justifying this decision.
What is recommended from a performance point of view? I am guessing that the join should result in the first option being slower.
What about indexes that could be created to make the first option faster?
What you describe are not two options to solve the same problem. Your first version is a n:m relation and it's just the "default" way to model such a relation. Your second version is just a 1:m mapping. The difference is, that in the first case book can be written by multiple authors. In the second case every book is written by just one author.
So make that absolutly excplicit: Your two "options" are two completly different use cases. If it's really m:n, you MUST use the first one!
The first option is a many-to-many relation. You would use that if there can be more than one author of a book (or zero authors of a book).
The second option is a one-to-many relation. You would use that if there can be only one author of a book.
So, you should pick the solution that fits what you are trying to do. Using the first option when the second option fits only opens up for inconsistencies, i.e. you could end up with books without authors or books with multiple authors.
Regarding performance either works fine. As long as there is an index to use (which is normally created for keys), a join is not a problem. For the second option you would add an index for the AuthorId field to make the lookup efficient.
Here's a tricky normalization/SQL/Database Design question that has been puzzling us. I hope I can state it correctly.
You have a set of activities. They are things that need to be done -- a glorified TODO list. Any given activity can be assigned to an employee.
Every activity also has an enitity for whom the activity is to be performed. Those activities are either a Contact (person) or a Customer (business). Each activity will then have either a Contact or a Customer for whom the activity will be done. For instance, the activity might be "Send a thank you card to Spacely Sprockets (a customer)" or "Send marketing literature to Tony Almeida (a Contact)".
From that structure, we then need to be able to query to find all the activities a given employee has to do, listing them in a single relation that would be something like this in it simplest form:
-----------------------------------------------------
| Activity | Description | Recipient of Activity |
-----------------------------------------------------
The idea here is to avoid having two columns for Contact and Customer with one of them null.
I hope I've described this correctly, as this isn't as obvious as it might seem at first glance.
So the question is: What is the "right" design for the database and how would you query it to get the information asked for?
It sounds like a basic many-to-many relationship and I'd model it as such.
The "right" design for this database is to have one column for each, which you say you are trying to avoid. This allows for a proper foreign key relationship to be defined between those two columns and their respective tables. Using the same column for a key that refers to two different tables will make queries ugly and you can't enforce referential integrity.
Activities table should have foreign keys ContactID, CustomerID
To show activities for employee:
SELECT ActivityName, ActivityDescription, CASE WHEN a.ContactID IS NOT NULL THEN cn.ContactName ELSE cu.CustomerName END AS Recipient
FROM activity a
LEFT JOIN contacts cn ON a.ContactID=cn.ContactID
LEFT JOIN customers cu ON a.CustomerID=cu.CustomerID
It's not clear to me why you are defining Customers and Contacts as separate entities, when they seem to be versions of the same entity. It seems to me that Customers are Contacts with additional information. If at all possible, I'd create one table of Contacts and then mark the ones that are Customers either with a field in that table, or by adding their ids to a table Customers that has the extended singleton customer information in it.
If you can't do that (because this is being built on top of an existing system the design of which is fixed) then you have several choices. None of the choices are good because they can't really work around the original flaw, which is storing Customers and Contacts separately.
Use two columns, one NULL, to allow referential integrity to work.
Build an intermediate table ActivityContacts with its own PK and two columns, one NULL, to point to the Customer or Contact. This allows you to build a "clean" Activity system, but pushes the ugliness into that intermediate table. (It does provide a possible benefit, which is that it allows you to limit the target of activities to people added to the intermediate table, if that's an advantage to you).
Carry the original design flaw into the Activities system and (I'm biting my tongue here) have parallel ContactActivity and CustomerActivity tables. To find all of an employee's assigned tasks, UNION those two tables together into one in a VIEW. This allows you to maintain referential integrity, does not require NULL columns, and provides you with a source from which to get your reports.
Here is my stab at it:
Basically you need activities to be associated to 1 (contact or Customer) and 1 employee that is to be a responsible person for the activity. Note you can handle referential constraint in a model like this.
Also note I added a businessEntity table that connects all People and places. (sometimes useful but not necessary). The reason for putting the businessEntity table is you could simple reference the ResponsiblePerson and the Recipient on the activity to the businessEntity and now you can have activities preformed and received by any and all people or places.
If I've read the case right, Recipients is a generalization of Customers and Contacts.
The gen-spec design pattern is well understood.
Data modeling question
You would have something like follows:
Activity | Description | Recipient Type
Where Recipient Type is one of Contact or Customer
You would then execute a SQL select statement as follows:
Select * from table where Recipient_Type = 'Contact';
I realize there needs to be more information.
We will need an additional table that is representative of Recipients(Contacts and Customers):
This table should look as follows:
ID | Name| Recipient Type
Recipient Type will be a key reference to the table initially mentioned earlier in this post. Of course there will need to be work done to handle cascades across these tables, mostly on updates and deletes. So to quickly recap:
Recipients.Recipient_Type is a FK to Table.Recipient_Type
[ActivityRecipientRecipientType]
ActivityId
RecipientId
RecipientTypeCode
||| ||| |||_____________________________
| | |
| -------------------- |
| | |
[Activity] [Recipient] [RecipientType]
ActivityId RecipientId RecipientTypeCode
ActivityDescription RecipientName RecipeintTypeName
select
[Activity].ActivityDescription
, [Recipient].RecipientName
from
[Activity]
join [ActivityRecipientRecipientType] on [Activity].ActivityId = [ActivityRecipientRecipientType].ActivityId
join [Recipient] on [ActivityRecipientRecipientType].RecipientId = [Recipient].RecipientId
join [RecipientType] on [ActivityRecipientRecipientType].RecipientTypeCode = [RecipientType].RecipientTypeCode
where [RecipientType].RecipientTypeName = 'Contact'
Actions
Activity_ID | Description | Recipient ID
-------------------------------------
11 | Don't ask questions | 0
12 | Be cool | 1
Activities
ID | Description
----------------
11 | Shoot
12 | Ask out
People
ID | Type | email | phone | GPS |....
-------------------------------------
0 | Troll | troll#hotmail.com | 232323 | null | ...
1 | hottie | hottie#hotmail.com | 2341241 | null | ...
select at.description,a.description, p.* from Activities at, Actions a, People p
where a."Recipient ID" = p.ID
and at.ID=a.activity_id
result:
Shoot | Don't ask questions | 0 | Troll | troll#hotmail.com | 232323 | null | ...
Ask out | Be cool | 1 | hottie | hottie#hotmail.com | 2341241 |null | ...
Model another Entity: ActivityRecipient, which will be inherited by ActivityRecipientContact and ActivityRecipientCustomer, which will hold the proper Customer/Contact ID.
The corresponding tables will be:
Table: Activities(...., RecipientID)
Table: ActivityRecipients(RecipientID, RecipientType)
Table: ActivityRecipientContacts(RecipientID, ContactId, ...,ExtraContactInfo...)
Table: ActivityRecipientCustomers(RecipentID, CustomerId, ...,ExtraCustomerInfo...)
This way you can also have different other columns for each recipient type
I would revise that definition of Customer and Contact. A customer can be either an person or a business, right? In Brazil, there's the terms 'pessoa jurídica' and 'pessoa física' - which in a direct (and mindless) translation become 'legal person' (business) and 'physical person' (individual). A better translation was suggested by Google: 'legal entity' and 'individual'.
So, we get an person table and have an 'LegalEntity' and 'Individual' tables (if there's enough attributes to justify it - here there's plenty). And the receiver become an FK to Person table.
And where has gone the contacts? They become an table that links to person. Since a contact is a person that is contact of another person (example: my wife is my registered contact to some companies I'm customer). People can have contacts.
Note: I used the word 'Person' but you can call it 'Customer' to name that base table.