When building a category navigation system for a business directory with a many to many relationship, I understand that it is good practise to create a mapping table.
Category Table ( CategoryId, CategoryName )
Business Table ( BusinessId, BusinessName )
Category Mapping Table ( BusinessId, CategoryId )
When I join the Category table and Business table to create the mapping table would this then give me a table which contains every possible business and category relationship?
I have 800 categories and 1000 business listings. Would that then give me a table containing 800,000 possible relationships. If so how would I focus on only the relationships that exist? Would I have to go through all listings (800,000) marking them as true or false?
I have been getting really confused about this so any help would be much appreciated.
When using many-to-many relationships, the only realistic way to handle this is with a mapping table.
Lets say we have a school with teachers and students, a student can have multiple teachers and visa versa.
So we make 3 tables
student
id unsigned integer auto_increment primary key
name varchar
teacher
id unsigned integer auto_increment primary key
name varchar
link_st
student_id integer not null
teacher_id integer not null
primary key (student_id, teacher_id)
The student table will have 1000 records
The teacher table will have 20 records
The link_st table will have as many records as there are links (NOT 20x1000, but only for the actual links).
Selection
You select e.g. students per teacher using:
SELECT s.name, t.name
FROM student
INNER JOIN link_st l ON (l.student_id = s.id) <--- first link student to the link-table
INNER JOIN teacher t ON (l.teacher_id = t.id) <--- then link teacher to the link table.
ORDER BY t.id, s.id
Normally you should always use an inner join here.
Making a link
When you assign a teacher to a student (or visa versa, that's the same).
You only need to do:
INSERT INTO link_st (student_id, teacher_id)
SELECT s.id, t.id
FROM student s
INNER JOIN teacher t ON (t.name = 'Jones')
WHERE s.name = 'kiddo'
This is a bit of a misuse of an inner join, but it works as long as the names are unique.
If you know the id's, you can just insert those directly of course.
If the names are not unique this will be a fail and should not be used.
How to avoid duplicate links
It's very important to avoid duplicate links, all sorts of bad things will happen if you have those.
If you want to prevent inserting duplicate links to your link table, you can declare a unique index on the link (recommended)
ALTER TABLE link_st
ADD UNIQUE INDEX s_t (student_id, teacher_id);
Or you can do the check in the insert statement (not really recommended, but it works).
INSERT INTO link_st (student_id, teacher_id)
SELECT s.id, t.id
FROM student s
INNER JOIN teacher t ON (t.id = 548)
LEFT JOIN link_st l ON (l.student_id = s.id AND l.teacher_id = t.id)
WHERE (s.id = 785) AND (l.id IS NULL)
This will only select 548, 785 if that data is not already in the link_st table, and will return nothing if that data is in link_st already. So it will refuse to insert duplicate values.
If you have a table schools, it depends if a student can be enrolled in multiple schools (unlikely, but lets assume) and teachers can be enrolled in multiple schools. Very possible.
table school
id unsigned integer auto_increment primary key
name varchar
table school_members
id id unsigned integer auto_increment primary key
school_id integer not null
member_id integer not null
is_student boolean not null
You can list all students in a school like so:
SELECT s.name
FROM school i
INNER JOIN school_members m ON (i.id = m.school_id)
INNER JOIN student s ON (s.id = m.member_id AND m.is_student = true)
When I join the Category table and
Business table to create the mapping
table would this then give me a table
which contains every possible business
and category relationship?
Yes.
Would I have to go through all listings (800,000) marking them as true or false?
No, you need to use the ON-clause to set join-conditions.
SELECT <columns> FROM categories as c
INNER JOIN mapping AS m
ON m.CategoryId = c.CategoryId
INNER JOIN businesses as b
ON m.BusinessId = b.BusinessId
You should use mapping tables when you are trying to model a many-to-many or one-to-many relationship.
For example, in an address book application, a particular contact could belong to zero, one or many categories. If you set your business logic that a contact can only belong to one category, you would define your contact like:
Contact
--------------
contactid (PK)
name
categoryid (FK)
Category
--------------
categoryid (PK)
categoryname
But if you wanted to allow a contact to have more than one email address, use a mapping table:
Contact
--------------
contactid (PK)
name
Category
--------------
categoryid (PK)
categoryname
Contact_Category
--------------
contactid (FK)
categoryid (FK)
Then you can use SQL to retrieve a list of categories that a contact is assigned to:
select a.categoryname from Category a, Contact b, Contact_Category c where a.categoryid=c.categoryid and b.contactid=c.contactid and b.contactid=12345;
select a.categoryname
from Category a
inner join Contact_Category c on a.categoryid=c.categoryid
inner join Contact b on b.contactid=c.contactid
where b.contactid=12345;
you only put the real relationships in the mapping table. so on average fi a business is in 2 categories, then in your example, there would only be 2000 records in the mapping table, not 800,000
"When I join the Category table and Business table to create the mapping table" you don't join those two tables to create the mapping table. You create an actual physical table.
Related
Is this possible to join table with prefic column to another two table in MySQL
For Example First Customer table has column ID Name andSecond Supplier table has column ID Name and Third Purchase table has column ID Product Party
I want join these three table Purchase table column Party to both table Customer and Supplier column ID
Here cus_ mean ID form Customer table and
Here sup_ mean ID form Supplier table
Can any one solve this joining? without prefix Customer or Supplier table PRIMARY KEY
To join with customer table:
select * from purchase_table pt inner join Customer c on
select replace(pt.party,'cus_','')=c.id and pt.party like 'cus_%'
To join with supplier table:
select * from purchase_table pt inner join Supplier s on
select replace(pt.party,'sup_','')=s.id and pt.party like 'sup_%'
I am creating a fantasy football android app where getting the JSON data is done with php files and SQL. My problem involves 2 tables:
player_details
player_id (primary key)
first_name
last_name
user_team
(All id fields except PK are foreign keys linked to the player_id)
user_team_id (primary key)
goalkeeper_id
rightback_id
leftback_id
etc.
I want to be able to run a PHP script, with a simple select statement in it, that will display a user team's details. I also want to include the first and last name of the players, which are linked to the foreign keys in the user_team position id fields. However all I can do is display the user_teams details and the players_id only.
SELECT *
FROM user_team
WHERE user_id = '".$uid."'
In this case, you have to do as many JOINs as the number of positions you have for your teams.
Like,
SELECT u.user_team_name, p1.goalkeeper_name, p2.rightback_name, p3.leftback_name, ...
FROM user_team u
LEFT JOIN player_details p1 ON u.goalkeeper_id = p1.player_id
LEFT JOIN player_details p2 ON u.rightback_id = p2.player_id
LEFT JOIN player_details p3 ON u.leftback_id = p3.player_id
...
WHERE u.user_team_id = <some id>
Doable, but not really good.
Then, you may change your model, and introduce the third table, that ties the player with both team and position, like:
CREATE TABLE team_positions (
player_id INT,
team_id INT,
position TEXT,
FOREIGN KEY player_id
REFERENCES player_details(player_id)
FOREIGN KEY team_id
REFERENCES user_team(user_team_id)
);
To increase the consitancy of data, it could be further normalized by introducing the positions table, than you going to refer it in team_positions by id too.
In the meantime, user_team table would retain just the team details, like name & any other stuff you wanna put there (emblem, perhaps?), along with team id.
This way, you're going to have quite flexible structure. And that is pretty much usual the way of doing stuff in relational DB model.
first i want to sorry for my bad english :D
second , i have a project in my college in sql and php that the doctor asked me to make 4 tables ( clients , payment , project , flats )
clients table have a relation with payment table and project table with a foreign key , and project table have a relation with flats table
i can make an insert statment to show all information on clients,payment and project tables
( SELECT clients.name, payment.first_cash, project_type.type_of_flat
FROM clients
INNER JOIN payment ON clients.client_id = payment.client_id
INNER JOIN project_type ON clients.client_id = project_type.client_id
LIMIT 0 , 30 )
now i want to show information in flat table also ,,
project table has a relation with flats table
project table is the parent and flats table is the child
thanks in advance and sorry again for my bad english :D
__
why the row repeated now ?
enter image description here
You need to add another JOIN with flats table.
SELECT clients.name, payment.first_cash, project_type.type_of_flat
FROM clients
INNER JOIN payment ON clients.client_id = payment.client_id
INNER JOIN project_type ON clients.client_id = project_type.client_id
INNER JOIN flats ON flats.project_id = project_type.project_id
LIMIT 0 , 30
In JOINS, you join two tables with an id field.
First table has actual data and the id field generally is its Primary Key.
Second table has reference with first table's id field which is Foreign Key.
I'm wondering how I can use JOIN or LEFT JOIN to group users.
users table:
id (primary)
user (varchar)
pass (varchar)
email (varchar)
website (varchar)
bio (text)
avatar (varchar)
code (varchar)
active (varchar)
admin (varchar)
group_1 (int) <--- I have a feeling that this is the wrong way to go about it
group_2 (int) <---
group_3 (int) <---
groups table:
group_id (primary key)
group_name (varchar)
group_bio (text)
group_website (varchar)
I was wondering how I could let a member be part of several groups and to show a list of members of a certain group..
Something like this:
Group Name
Users: <a href='profile'>Name</a>, <a href='profile'>Name</a>, <a href='profile'>Name</a>, <a href='profile'>Name</a>
I have absolutely no idea how to go about this. Please help.
You want a standard many-to-many relationship.
This is usually implemented by having three tables.
Users
Groups
Memberships
The memberships table will have two foreign keys, which map on to the other two tables.
You have to create a new table MEMBER_GROUPS with two fields: user_id and group_id.
Every row is a membership of a user...
In this way you can easily query user membership in a group...
This is indeed the wrong approach, as it restricts a user to three group memberships. This is a classic many-to-many relationship, and you can model it using a bridge table:
user_group
----------
user_id
group_id
The primary key will be a composite of user_id and group_id, enforcing uniqueness. Then you would do a double-join through this table. For example, to get all of the members of all of the groups:
SELECT group.*, user.*
FROM group
LEFT OUTER JOIN user_group
ON group.group_id = user_group.group_id
LEFT OUTER JOIN user
ON user_group.user_id = user.user_id
Or, if you are after a specific group:
SELECT user.*
FROM user_group
INNER JOIN user
ON user_group.user_id = user.user_id
WHERE user_group.group_id = ?
You could even get a list of all groups, with membership count:
SELECT group.*, COUNT(user_group.user_id) AS group_membership_count
FROM group
LEFT OUTER JOIN user_group
ON user_group.group_id = group.group_id
GROUP BY group.group_id
I am very new to mysql and databases, so I need help here...
How should I use JOIN to fetch a record from the tables below, when the only given variable is the ad_id?
category and category options are filled in manually i.e. the users may not alter them. So they are only reference tables, but I am not sure this is how I should do it...
I have 6 tables:
category:
cat_id (PK)
cat_name
category_options:
option_id (PK)
cat_id (FK)
option_name
option_value:
value_id (PK) (AI) // I think this should have Auto Increment
option_id (FK)
classified_id (FK)
value
classified: (THIS IS THE MAIN TABLE YOU COULD SAY)
classified_id (PK) (AI)
ad_id
cat_id
headline
description
area: // I am thinking about moving these fields over to the posters table, right?
area_id (PK)
classified_id (FK)
area
description
Here is how I insert a classified into the tables:
mysql_query("INSERT INTO classified (ad_id, cat_id, headline, description) VALUES ('$ad_id', $cat_id, '$headline', '$description')");
$last_classified_id=mysql_insert_id();
mysql_query("INSERT INTO poster (classified_id, name, email, tel) VALUES ($last_classified_id, '$name', '$email', '$tel')");
mysql_query("INSERT INTO area (classified_id, area, community) VALUES ($last_classified_id, '$area', '$community')");
I am new to JOIN!
Every category has sub options (CARS -> color) and every option has a value.
I want to, only by having the ad_id, select all this information.
How can I do so?
And should I merge the area and posters table?
Also, please take a careful look at my db, and tell me if there is anything I might have missed...
This is really out of my knowledge-base so detailed explanations are appreciated!
Thanks
It looks like you have two fields that could be the primary key in classified: classified_id and ad_id. Then you have two other tables, poster and area, that have a one-to-one correlation with classified. If this is the case, you could put all the fields in classified.
A query to join the tables in your insert statements would like like this:
select
classified.ad_id,
classified.classified_id,
classified.headline,
classified.description AS classified_description,
poster.name,
poster.email,
poster.tel,
area.area,
area.description AS area_description from
classified inner join
poster
on
classified.ad_id = poster.classified_id inner join
area
on
classified.classified_id where
classified.ad_id = 123
This is an example of joining some of your tables to get data from more than one of them:
SELECT c.cat_name, co.option_name, cl.headline
FROM category c
INNER JOIN category_options co ON co.cat_id = c.cat_id
INNER JOIN classified cl ON cl.cat_id = c.cat_id
WHERE cl.ad_id = {Your ad_id}
You can join to any other tables needed in the same way (poster, area).
Edit (response to comment): The 'c', 'cl', and 'co' are aliases for the 'category', 'classified', and 'category_option' tables. They don't have anything to do with the join. Here's a source. When I say FROM category c, that allows me to use 'c' as the a shortcut for the category table. Using aliases allows you to make the select/joins/where clause how I did instead of like this:
SELECT category.cat_name, category_options.option_name, classified.headline
FROM category
INNER JOIN category_options ON category_options.cat_id = category.cat_id
INNER JOIN classified ON classified.cat_id = category.cat_id
WHERE classified.ad_id = {Your ad_id}
Basically it's a shortcut that can save you some typing.