I've been reading up on normalization and relationships and am curious -- is the only point of a junction table to store attributes that don't make sense in either of the parent tables?
For example, if you have a Chat and Users table, and a chat can have many users and visa versa, couldn't you just have a one-to-many relationship on both tables without a junction table?
That is, couldn't you say that a chat has many users and that a user has many chats?
Why would you have to create a table such as ChatUsers and then say that a chats has many chatUsers and that a user has many ChatUsers?
The only reason I can think of is that you want to add attributes like number of undread messages per chat, or notification settings, which only make sense in a ChatUsers table.
If this is not the case, and you don't need to add anything, does the concept of many-to-many even make sense? wouldn't it just be easier to think of it as two one-to-many relationships?
The use of the junction table takes your data to its lowest possible normalised level, it should be used where there is something that could be duplicated across multiple entires such as a date or a time.
I cannot think of a specific example with a Chat and Chat User table, but one ive come across a lot is in relation to addresses.
As individuals both you and myself could live at the same address, but at different times. It wouldnt be appropriate to hold a date of when I lived at an address in a user table (as I could live at multiple addresses). It also wouldnt be appropriate to record a date in the address table (as this could lead to multiple address lines), as such you should end up with tables with the following design and data.
User_Table
User_Id
User_Name
U1
John Smith
U2
Jane Smith
U3
Rebecca Smith
Address_Table
Address_Id
Address
AD1
1 High Street
AD1
2 High Street
AD1
3 High Street
AD1
4 High Street
Address_History_Table
Add_His_ID
User_Id
Address_Id
Start_Date
End_Date
AH1
U1
AD1
01/09/2000
01/01/2019
AH2
U1
AD2
02/01/2019
31/08/2022
AH3
U2
AD1
02/01/2019
AH4
U3
AD2
01/08/1965
31/08/2022
In this example U1 (John Smith) and U2 (Jane Smith) have both lived at address AD1(1 High Street) but not at the same time. In this example Jane moved in (02/01/2019) the day after John moved out (02/01/2019).
U1 (John Smith), then moved into AD2 (2 High Street) from the 02/01/2019 with no end date. U3 (Rebecca Smith) lived in this address already (start_date of 01/08/1965) and lived there until 31/08/2022.
From this we can identify that John and Jane havent lived together, while John and Rebecca did (From the 02/01/2019 to 31/08/2022).
The use of the junction table will very much depend on your data. In your chat example if two users were in the same chat for the exact same time, could lead to a duplication if a time for example was recorded.
A juntion table can sometimes just be three columns
Primary Key of the table
Foreign Key of the user table
Foreign Key of the chat table
The junction table would then just be used to denote which chat linked to which user, and dosent need to contain any other information.
Related
Guys iam working with an online quiz examination project.
i have a small doubt. basically user table is for registering users.
in my application iam the organization. my team has more than 5 users with different roles. I know about roles and permissions. our role is to upload questions in the db.
so lots of school will register and the staff memebers and students in the school are users of my application.
the role of staff is to create assessment by choosing the questions which is already stored in db.
after creating assessment student are requested to login and then write the exam. then results are verified.
Here my doubt is
as a oraganization iam also user here, the students and staff members of different schools also user here.
then how my user table must be changed.
this my structure
As my organization i will get
name
user_name
email
phno
password
these data are enough for my team. but when it comes to school say for example
AAA matriculation Higher Secondary school is registering to our application so i need to get the school info like school name, school address, school phno etc.
then i should register the student and staff members of that school
like
Staff A belongs to this school with this username and this password with this role with this subject ( so that when the staff login he/she can see only maths questions)
Student B belongs to this school with this username and this password with this role and this class(then only those class assessments will be shown to him/her)
so my
schoolDetails Table
id name address phno
1 School1 Address1 123
2 School2 Address2 321
3 School3 Address3 547
.
.
so on
when registering staff or student of that school
id school_id name username email password phno
1 1 A AAA a#gm ** 122
2 1 B BBB b#gm ** 789
so if i i have a user table like above then how i can register my team??
overal my doubt is how to register my team, and other school in users table
i know that i will have a class table and subject table which will be linked to user table so based on the staff or student login that changes the display screen.
My major doubt how can i register myself and them??
I would split it a bit differently.
Schools, ok
User: defines users only, without any links to schools, yet
User type: defines types that each user can have
Register: links schools and users
So if your user is strictly an administrator, and not a student, you ommit that user from the register table. This way you can even have a student take classes in two schools (if that is possible with your logic). At least is decouples schools and users (and is good for normalization anyway).
As a general rule, defines what objects you have in your requirements. Each of those become one table. Then list your relations. Single (1-1) relations become foreign keys, (many-many, 1-many) become link tables.
Tables...
Schools
ID NAME ADDRESS PHONE
1 School1 Address1 514-123-1324
2 School2 Address2 514-123-1234
...
User
ID TYPE NAME USERNAME PASSWORD PHONE
1 1 AAA usera passa 514-123-1234
2 2 BBB userb passb 514-123-1234
...
User Type
ID TYPE
1 Admin
2 Student
...
Register
ID SCHOOLID USERID
1 1 1
2 1 2
...
i am trying to make up this situation in my app: there are users who can select the languages they speak (such as english, spanish, japanese and so on) and users who can confirm the languages selected by others users (like in LinkedIn, where you can confirm the skill of another person).
I have 4 tables in a DBRM: Users, Languages, Users_Language and Users_Confirmations.
The bodies:
Users
id name lastname ...
Languages
id name
Users_Languages
user_id language_id
Users_Confirmations
user_id language_id other_id ------> here other_id refers to Users table, like user_id. They both refer to Users table, since an user can confirm another user
For example:
John Smith speaks English, Spanish and Danish.
Luke Red and Jennifer Brown confirmed English on John Smith.
Now, I want to get all Users who, for example, have confirmed the user with id "4", and show them in a HTML list. And I would want to get it with both PURE SQL and Laravel (Eloquent or Query Builder).
Thank you in advance!
Here you have to change your table attributes to avoid repetition, use just
Users_Languages_ID as a foreign key to refer to the Users_Langages table
-- Users_Confirmations
confirmation_id user_language_id
You can just use Users_Confirmations, and for each confirmation added, you will insert a row that contains user_language_id
Returning to the question(to get users who confirmed the user with id "4")
SELECT Users.name, Users.lastname, Languages.name
FROM Users_Confirmations
JOIN Users_Languages ON Users_Languages.id = Users_Confirmations.user_language_id
JOIN Languages ON Languages.id = Users_Languages.language_id
JOIN Users ON Users.id = Users_Languages.user_id
WHERE Users_Languages.user_id = 4
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 making a simple tennis database that features:
Tournaments (Mens/womens singles, Mens/womens doubles, Mixed doubles)
Players
Results
My Results table looked something like
ResultID
DatePlayed
Player1ID (became ParticipantID1)
Player1Score
Player2ID (became ParticipantID2)
Player2Score
I then realised that a player could play in more than one tournament so I needed another table, Participant (or could be called team, or couple).
ParticipantID
PlayerID
TournamentID
With all three ID's being composite.
Now Joe (ID: 1) and Tom (ID: 2) can be a doubles partner but Joe can still play in the Singles
Participant ID -- PlayerID -- TournamentID
1 ----------------- 1 ------------ 1
1 ----------------- 2 ------------ 1
2 ----------------- 1 ------------ 2
Now the problem I have with this is that auto-increment/identify would have to be turned for the Participant table meaning more coding work would have to be done (when creating and validating etc).
The second problem I have with this is that all the singles players data would be repeating, as they would be stored in the Player table and also the Participant table.
I could have another Results table, i.e. DoubleResults, but I feel this isn't necessary.
Is this the only way it can be done or has my mind just gone blank?
A tournament will have many matches. Therefore you need a one to many relationship between tournaments and matches.
A match will have a type (singles, doubles, etc). So your match table has to include a type id.
You will need a many to many relationship between teams and matches. A team can have either one or two players, depending on the type of match. At this point, it comes down to how much detail you want to store. It might be simply good enough to store the winning team id in this table.
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.