Foreign key for many to many relationship in sql - sql

I have an SQL table called Listing which is representing houses that have been rented. The table has a primary key id and another field called amenities with the things each house had to offer. The amenities of each house are separated from each other with a comma. For example TV, Internet, Bathroom.
I used the following commands to create a table called Amenity with all the unique different amenities offered and a SERIAL number for each amenity.
CREATE TABLE Amenity AS(
SELECT DISTINCT regexp_split_to_table(amenities,',') FROM Listing
);
ALTER TABLE Amenity
RENAME regexp_split_to_table to amenity_name;
ALTER TABLE Amenity ADD COLUMN amenity_id SERIAL;
ALTER TABLE Amenity ADD PRIMARY KEY(amenity_id);
My problem is that I need to connect these two tables with a foreign key and I don't know how since the relationship between them is a many to many relationship. I have checked other questions regarding foreign keys in many to many relations but could not find anything similar. If there exists something similar please explain the way it is similar to my question.

You must create another table which will hold the one-to-many relationships between a house and its amenities.
So your 3 tables looks look like this:
Table HOUSE
+----------+------------+
| house_id | house_name |
+----------+------------+
| 1 | Uncle Bob |
+----------+------------+
| 2 | Mom Sara |
+----------+------------+
Table AMENITIES
+------------+--------------+
| amenity_id | amenity_name |
+------------+--------------+
| 1 | TV |
+------------+--------------+
| 2 | Internet |
+------------+--------------+
| 3 | Kitchen |
+------------+--------------+
Table HOUSE_AMENITIES
+----------+------------+
| house_id | amenity_id |
+----------+------------+
| 1 | 1 |
+----------+------------+
| 2 | 1 |
+----------+------------+
| 2 | 2 |
+----------+------------+
| 2 | 3 |
+----------+------------+
So the house Uncle Bob has only TV while the house Mom Sara has TV, Internet and a fully equipped kitchen.
Remember - you should never use the same column to store multiple values (separated with comma). In all such cases you have to use another table, converting the multiple comma-separated values into distinct rows inside this detail table and referencing the primary key of the master table.

Related

Select unique combination of values (attributes) based on user_id

I have a table that has user a user_id and a new record for each return reason for that user. As show here:
| user_id | return_reason |
|--------- |-------------- |
| 1 | broken |
| 2 | changed mind |
| 2 | overpriced |
| 3 | changed mind |
| 4 | changed mind |
What I would like to do is generate a foreign key for each combination of values that are applicable in a new table and apply that key to the user_id in a new table. Effectively creating a many to many relationship. The result would look like so:
Dimension Table ->
| reason_id | return_reason |
|----------- |--------------- |
| 1 | broken |
| 2 | changed mind |
| 2 | overpriced |
| 3 | changed mind |
Fact Table ->
| user_id | reason_id |
|--------- |----------- |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 3 |
My thought process is to iterate through the table with a cursor, but this seems like a standard problem and therefore has a more efficient way of doing this. Is there a specific name for this type of problem? I also thought about pivoting and unpivoting. But that didn't seem too clean either. Any help or reference to articles in how to process this is appreciated.
The problem concerns data normalization and relational integrity. Your concept doesn't really make sense - Dimension table shows two different reasons with same ID and Fact table loses a record. Conventional schema for this many-to-many relationship would be three tables like:
Users table (info about users and UserID is unique)
Reasons table (info about reasons and ReasonID is unique)
UserReasons junction table (associates users with reasons - your
existing table). Assuming user could associate with same reason
multiple times, probably also need ReturnDate and OrderID_FK fields
in UserReasons.
So, need to replace reason description in first table (UserReasons) with a ReasonID. Add a number long integer field ReasonID_FK in that table to hold ReasonID key.
To build Reasons table based on current data, use DISTINCT:
SELECT DISTINCT return_reason INTO Reasons FROM UserReasons
In new table, rename return_reason field to ReasonDescription and add an autonumber field ReasonID.
Now run UPDATE action to populate ReasonID_FK field in UserReasons.
UPDATE UserReasons INNER JOIN UserReasons.return_reason ON Reasons.ReasonDescription SET UserReasons.ReasonID_FK = Reasons.ReasonID
When all looks good, delete return_reason field.

Is it better to use a separate table to store a list of values, or include the value directly in the current table?

I have a jobs table that stores information such as title, department, and salary. I'm wanting the user to be able to create a job using a form that has fields for the aforementioned information, as well as a field for the job category. category would be something like retail, or IT, for example.
I don't have any issues with the actual coding itself, but rather what the best way to design the database store the information in it. So my question is this: should I create a separate table categories that stores each job category, along with an ID, so that the tables would look something like this
categories jobs
+----+---------------+ +----+---------------+-------------+--------+-------------+
| id | category | | id | title | department | salary | category_id |
+----+---------------+ +----+---------------+-------------+--------+-------------+
| 1 | Retail | | 1 | Retail | department1 | 10000 | 2 |
+----+---------------+ +----+---------------+-------------+--------+-------------+
| 2 | IT | | 2 | IT | department2 | 12000 | 1 |
+----+---------------+ +----+---------------+-------------+--------+-------------+
where category_id is a foreign key linking to the categories table,
or should I do something like this, where all the information is stored in a single table:
jobs
+----+---------------+-------------+--------+-------------+
| id | title | department | salary | category |
+----+---------------+-------------+--------+-------------+
| 1 | Retail | department1 | 10000 | IT |
+----+---------------+-------------+--------+-------------+
| 2 | IT | department2 | 12000 | Retail |
+----+---------------+-------------+--------+-------------+
Which is the better option? They both seem to achieve the same result, but what are the pros and cons of doing it either way, and which way would be the more preferred way of doing it?
In general, you want to store "entities" in separate tables. In this case, category is a separate entity from jobs.
Why do you want to do this?
There is only one row per category, so you don't have to worry about duplication -- and errors.
There may be additional information that you want to store, such as the creation date, abbreviation, who created it, and so on.
Properly declared foreign key constraints ensure that only valid categories are stored.
Categories may be shared across different tables, and a separate reference table ensures that the values are consistent.

How can I separate out multiple values from a column via another table?

I have a table named Team. Each record can have more than one member. Rather than jamming members comma separated value, I am hoping to use separate table to meet the requirement. Id is primary key.
----------------------------
| Id | Name | Member
----------------------------
| 1 | TeamA | Jim, Jack
----------------------------
| 2 | TeamB | Micah
I thought of creating a table named User. UserId is the PK and TeamId is FK.
--------------------------
| UserId | Name | TeamId
--------------------------
| 123 | Jim | 1
--------------------------
| 456 | Jack | 1
--------------------------
| 789 | Micah | 2
Then I want parent table Team be able to refer Jim and Jack from its child table but I am not sure how to represent it in one to many relationship... I know below expression is not correct....
------------------------
| id | Name | Member
------------------------
| 1 | TeamA | 123, 456
(Table) Team:
TeamId(PK), Name
(Table) Member:
MemberId(Pk), Name
Case 1 (one to many):
Every Member can be in one team:
Simply add TeamId(FK) to Member Table
Case 2 (many to many):
Every Member can be in as many teams as you want:
Add a linking table:
(Table) TeamMember:
TeamId(FK), MemberId(FK)
That indeed means to normalize data further meaning to split tables your data isnt atomic at each column level. Hence should be normalized to avoid difficulties in data retrievel.
Users Table
User Id(pk) TeamId(fk)
Members Table
TeamId(pk) , MemberId, NAME
Query
Select
u.userid, memberid, m.namefrom
users u join members m
On u.userid=m.memberid and
u.teamid=m.teamid
It looks like you need to create a mapping table to represent the Team, Member relationship, which would make this a many-to-many relationship.
TeamMemberMap - TeamId, MemberId

Supertype & Subtypes and one to one relationship

I have the following supertype/multiple subtypes tables in SQL Server
supertype: Doctor and subtypes: Paediatrician, Orthopedic and Dentist
create table Doctor
(
DoctorID int primary key,
Name varchar(100),
-- add some other common attributes (all of vendor, sponsor, volunteer have) here.
)
create table Paediatrician
(
PaediatricianId int primary key,
DoctorID int foreign key references Doctor(DoctorID)
-- add some other attributes related to Paediatrician here.
)
create table Orthopedic
(
OrthopedicId int primary key,
DoctorID int foreign key references Doctor(DoctorID)
-- add some other attributes related to Orthopedic here.
)
create table Dentist
(
DentistId int primary key,
DoctorID int foreign key references Doctor(DoctorID)
-- add some other attributes related to Dentisthere.
)
My business logic is that a doctor can be either a Paediatrician, Dentist or an Orthopedic. Cannot be more than one of the subtypes. Based on the above design this is not enforced. I can create Doctor with Id = 1 and then go to Dentist and Orthopedictables and assign DoctorId value of 1 in both tables. How do I enforce it so that a doctor can be present at only one table?
I would arrange this bit differently. I would have 3 tables, a Doctor table (like you already have), a Specialist table and a SpecialistAttributes table.
The Doctor table contains all the Doctors' info, easy.
The Specialist Table contains your SpecialistTypeID and SpecialistDescription etc.
Your 3 example specialists would each be a row in this table.
The SpecialistAttributes table contains all the attributes needed for the specialists. In your Doctor table, you have a foreign key to lookup the SpecialistTypeID, so there can be only 1, then the SpecialistType has a number of SpecislaistAttibutes it can link to.
The other benefit of organising your data this way is that of you need to add any specialists roles or attributes, you don't need to change the structure of your database, just add more rows.
Doctor Table
| ID | Name | Specialist_FK |
---------------------------------
| 1 | Smith | 2 |
| 2 | Davies | 3 |
| 3 | Jones | 3 |
Specialist Table
| ID | Speciality |
----------------------
| 1 | Paediatrician |
| 2 | Orthopedic |
| 3 | Dentist |
SpecialistAttribute Table
| ID | SpecialityID+FK | Description | Other |
------------------------------------------------------------
| 1 | 1 | Paediatrician Info 1 | Other Info |
| 2 | 1 | Paediatrician Info 2 | Other Info |
| 3 | 2 | Orthopedic Info 1 | Other Info |
| 4 | 2 | Orthopedic Info 1 | Other Info |
| 5 | 3 | Dentist Info 1 | Other Info |
| 6 | 4 | Dentist Info 1 | Other Info |
There is no inbuild constraints/feature in the SQL server to handle this. You need to write custom login for it. Either in the procedure or Trigger.
You can write a stored procedure which would be responsible to insert in these tables. before insert, it will validate that if doctor id already exists in any of the tables if yes then an error will be custom raised otherwise procedure will insert the record in the respective table.

Parent Child Concept in SQL Server Relational Database

I have a Teacher and a Student table in SQL Server. I want to use the inheritance concept to make a table with the name Person and put the common attributes of Student and Teacher there.
Practically how can I do it?
What I want to know is:
how a Person record will show in Student table?
If I update the name from Student how will it get updated in Person table and etc.
Please help me I don't know anything about to try and I need it badly please...
"Teacher" and "student" would be your tables that inherit from "Person".
person stores all the details that are common for both teachers and students (eg, name, address, contact info etc)
teacher stores specific info for teachers, and a foreign key pointing to the person table to identify their personal information. similarly, student stores information specific to students
your person table could look like
+-----------+---------+----------+------------+
| person_id | fname | lname | dob |
+-----------+---------+----------+------------+
| 1 | tracey | wright | 10/10/1990 |
| 2 | max | smith | 11/11/1998 |
| 3 | chris | brown | 12/06/1978 |
+-----------+---------+----------+------------+
lets assume that tracey and max are students, and max is a teacher.
Your teacher table could look like
+------------+-----------+------------+
| teacher_id | person_id | speciality |
+------------+-----------+------------+
| 1 | 3 | maths |
+------------+-----------+------------+
teacher_id is the table identifier, and person_id is the the one that chris has in the person table. This now identifies chris as a teacher
Similarly, your student table could look like
+------------+-----------+------------+--+
| student_id | person_id | detentions | |
+------------+-----------+------------+--+
| 1 | 1 | 4 | |
| 2 | 2 | 5 | |
+------------+-----------+------------+--+
This now identifies tracey and max as students (and for example, specific information regarding the students might be number of detentions)
In each case, with teacher and student, person_id is used as a foreign key. Foreign keys are primary keys within another table, thus allows other tables to reference each other.
In order to access the information for each record, you would need to use a join statement. Depending in the DBMS you are using, this varies in syntax (see http://www.w3schools.com/sql/sql_join.asp to get a proper understanding)
Here you can learn about creating relationship between tables..
https://www.simple-talk.com/sql/t-sql-programming/questions-about-primary-and-foreign-keys-you-were-too-shy-to-ask/