this question may asked by several people.But still I didn't get a right answer. So here it is
I want to load Continents, Countries and Cities to below combo boxes. So I need to make relation between those. Means city need be in a country and country belongs to a continent. So of course I am talking about a tree structure. So how should I implement this in MYSQL database in efficient way? How many tables need? How to do the relation among those?
Here is the image.
http://i.stack.imgur.com/st4oz.jpg
There are formal ways to represent arbitrary trees, but I think the following is simpler and should be sufficient:
CREATE TABLE Continents (
id INT AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
PRIMARY KEY (id),
UNIQUE (name)
)
CREATE TABLE Countries (
id INT AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
continent INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (continent) REFERENCES Continents(id),
UNIQUE (name)
)
CREATE TABLE Cities (
id INT AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
country INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (country) REFERENCES Countries(id),
UNIQUE (name)
)
I didn't test the code, so there may be some syntax errors. I hope the intent is clear, though.
#Vmai raises an excellent point in his comment on the question.
My solution would be to have the "problem countries" once in the Countries table for every continent they are in. (So Turkey would be twice in the database, once with continent set to the id of Asia, and once to the id of Europe. Same for Russia.) The same goes for cities, of course.
All you need is one table. As long as the structure of data is the same, there's no reason to have three tables. And this way, you don't care about the depth and how the locations administratively are organized.
+-------------------------+
| locations |
+-------------------------+
| location_id (int) | primary key
| location_name (varchar) |
| parent_id (int) | index
+-------------------------+
Or another solution
+-------------------------+
| locations |
+-------------------------+
| location_id (int) | primary key
| location_name (varchar) |
| left (int) |
| right (int) |
+-------------------------+
To be explained...
Related
I have the following tables:
TABLE country
(
country_id int not null,
name varchar(32) not null,
primary key (country_id),
unique key (name)
);
TABLE place
(
place_id int not null,
name varchar(32) not null,
country_id int not null,
primary key (place_id),
unique key (country_id, name)
);
TABLE image
(
image_id int not null,
title varchar(75) not null,
caption varchar(500) not null,
filename varchar(29) not null,
country_id int,
place_id int,
primary key (image_id),
unique key (filename)
);
An image can have a country (or not) or a place (or not).
Let’s say that I have a record in the country table:
23 | Spain |
And places in the place table:
3 | Madrid | 23
6 | Barcelona | 23
I want to tag an image with the country Spain and a place Barcelona
In the image table, should I enter the country_id and the place_id or just the place_id since the country is already determine by the place_id?
Polymorphic relationships are not easy to model in a relational database.
Here, I would suggest another approach that what you have set up: build two different bridge tables for images - one for countries, and the other for places.
That would look like:
create table countries (
country_id int primary key,
...
);
create table places (
place_id int primary key,
...
);
create table images (
image_id int primary key,
...
);
create table image_countries (
image_id int references images(image_id),
country_id int references countries(country_id),
primary key (image_id, country_id)
);
create table image_places (
image_id int references images(image_id),
place_id int references places(place_id),
primary key (image_id, place_id)
);
You are then free to link a given image to as many places and countries as you like. If you want, instead, to allow just one country and one place per image, you can change the primary key of each bridge table to just image_id.
Change your mental focus. Focus on a "place" being associated with an image. Then make places work for both both "Spain" and "Madrid, Spain". Do not attempt to jump past places to get to countries.
So, in places, allow an empty name with a non-empty country to indicate "Spain".
I would use the standard 2-letter country codes instead of a 4-byte INT. Then I would either display "ES" with the images for Spain or have a lookup table like your current countries.
I have project for school competition in timekeeping and I am stuck to solve tables construction.
Look at this following examples.
This can happen ->
Competition | Contestants
Swiming | John Smith
Driving | John Smith
You can see that same name is there twice, but not in same competition.
This situation is wrong, so how can i prevent following situation ->
Competition | Contestants
Swiming | John Smith
Swiming | John Smith
I want to avoid duplication in the same competition.
If you can't change the table structure of the table, you could add a unique constraint on the combination of the competition and contestant:
ALTER TABLE competitions
ADD CONSTRAINT competitions_unq UNIQUE (competition, contestant);
But this really isn't a great solution. A more idiomatic approach would be to have separate tables for competitions and contestants, and then have an m:n table to join them:
CREATE TABLE competitions (
id INT PRIMARY KEY,
name VARCHAR(100),
-- other columns
);
CREATE TABLE contestants (
id INT PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100),
-- other columns
);
CREATE TABLE competition_contestants (
competition_id INT NOT NULL,
contestant_id INT NOT NULL,
PRIMARY KEY (competition_id, contestant_id),
FOREIGN KEY competition_id REFERENCES competition(id),
FOREIGN KEY contestant_id REFERENCES contestant(id)
);
I am looking to build a sports database where the user selects a country from a list 15 different countries, that then presents different divisions within that country. The user then selects a division and is presented with a list of teams within that division to select.
One approach I had been advised to take is to have separate tables for Countries and Teams.
Table - Countries
Country | Teams (int array)
Table - Teams
ID (int) | Team Name | Division
The 'Teams (int array) would match with the ID of the team name in Teams Table.
I'm not 100% sure this is the correct approach.
What other solutions would be advisable?
You should create three tables. Something like
create table countries(
id int unsigned auto_increment primary key,
name varachar(100) not null,
unique key (name)
);
create table divisions(
id int unsigned auto_increment primary key,
country_id int unsigned not null,
name varchar(100) not null,
unique key uk_name (name),
foreign key fk_countries (country_id)
references countries(id)
on update restrict
on delete cascade
);
create table teams(
id int unsigned auto_increment primary key,
division_id int unsigned not null,
name varchar(100) not null,
unique key uk_name (name),
foreign key fk_divisions (division_id)
references divisions(id)
on update restrict
on delete cascade
);
Your queries would be..
Show all countries:
select id, name from countries;
After the user selects a country you know the ID of that country and you can show all divisions from that country:
select id, name from divisions where county_id = ?;
Now the user selects a division and you get its ID - so you can show all teams from that division:
select id, name from teams where division_id = ?;
You don't need to store the teams in the country table. Just have a countries table with the names of the countries. In the teams table, have an column for the country which uses the index of the country table. Now you can search for all teams in a given country. For example;
select teamName, otherTeamData from teamTable where countryIndex = selectedCountryIndex and divisionIndex = selectedDivisionIndex;
You also need a divisions table which will likely have a countryIndex as well. Then you present a list of divisions specific to any country.
I'm normalizing at the moment in 2NF and I'm quite confused, Here is what i have so far in 0 NF Colour is a multi valued attribute of Product
Product = Product_ID (PK)
Colour{Colour ID, Colour_Name}
Then in 1NF colour gets its own table so its
Colour=
+Colour_ID (PK)
+Product_ID (FK)
+Colour_Name
in 2NF its then changed to 2 Separate Tables
Colour =
+Colour_ID (PK)
+Product_ID(FK)
and a new table
Product_Colour =
+Colour_ID
+Colour_Name
I'm i've finished out the ERD and doing the mySQL but are they (Colour_ID) both primary keys respectively or is one a foreign key, but if one is then a foreign key do i need a primary key for that table?
Thanks,
You definitely need a colour table:
colour_id INT PRIMARY KEY
colour_name VARCHAR(255) # or other appropriate data type
Then, if you know that each product will always have exactly two colours, your product table might look like this:
product_id INT PRIMARY KEY,
color1 INT NOT NULL FOREIGN KEY (colour.colour_id),
color2 INT NOT NULL FOREIGN KEY (colour.colour_id)
You could drop the second NOT NULL in case products will always have one or two colours.
The more flexible approach would be to use a third table, allowing you to add an arbitrary number of colours to each product:
product table:
product_id INT PRIMARY KEY
product_colors table:
product_id INT FOREIGN KEY (product.product_id)
colour_id INT FOREIGN KEY (colour.colour_id)
PRIMARY KEY(product_id, colour_id)
So, in this case, both id fields are foreign keys on their own while together forming the primary key so it's impossible to add the same colour to the same product twice.
(pseudo SQL syntax used)
I visualize this:
Product = Product_ID (PK), Colour_ID (FK)
Colour = Colour_ID (PK), Colour_Name
________________________ _________________________
| Product_ID | Colour_ID | | Colour_ID | Colour_Name |
-------------------------- ---------------------------
|____________|___________| |___________|_____________|
So I understand how to create foreign keys and I know what is the purpose of the FK. But I have a problem in understanding How to use them. I asked a question regarding Foreign keys HERE(Click link)
Here is what I made:
CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
FOREIGN KEY (i_id) REFERENCES items(i_id),
FOREIGN KEY (name) REFERENCES items(name),
FOREIGN KEY (id) REFERENCES user(id)
);
Now my question is how do I make the most out of this using PHP? From the link above, people have suggested that it's good to use only one foreign key in the user_purchase table, but what if I want several columns? Why don't we use several foreign keys for different columns of the same table?
I am using mysql and php. I would appreciate it if you could show some examples of how you use PHP with the tables which have foreign keys to get get information using MYSQL commands. I really need a thorough explanation.
I also need to understand the terms Normalization and Denormalization. I would appreciate if you could give some links which explain these terms in great detail with examples or if you have any suggestion for some great books for beginners in database design, implementation, etc, I would really appreciate.
Thanks a lot.
Foreign key columns/constraints disambiguation
So I understand how to create foreign keys and I know what is the
purpose of the FK. But I have a problem in understanding How to use
them.
Assuming you are referring to the foreign key constraints, the short answer would be you just don't use them.
And here comes the long one:
We are accustomed to refer to columns being foreign keys to other tables. Especially during the normalization process, phrases like "user_purchase.i_id is a foreign key to the items table" would be very common. While that's a perfectly valid way to describe the relationship, it can get a little fuzzy when we reach the implementation phase.
Suppose you have created your tables without the FOREIGN KEY clauses:
CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
);
Notice that, relation-wise, the foreign key columns are still implemented. There's a column that references the user table (id) and another one that references the items table (i_id) -- let's put the name column aside for a moment. Consider the following data:
user user_purchase items
| id username | | id i_id | | i_id name price |
| 23 john | | 55 10 | | 10 chocolate bar 3.42 |
| 55 mary | | 70 10 | | 33 mobile phone 82.11 |
| 70 fred | | 70 33 | | 54 toothpaste 8.67 |
| 55 10 | | 26 toy car 6.00 |
| 70 26 |
The relation is there. It is implemented by means of the user_purchase table, which holds information as to who bought what. If we were to query the database for a relevant report, we would do:
select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
And that's how we use the relation and the foreign key columns involved.
Now, what if we do:
insert into user_purchase (id,i_id) values (23,99)
Apparently, this is an invalid entry. Although there is a user with id=23, there's no item with i_id=99. The RDBMS would allow that to happen, because it doesn't know any better. Yet.
That's where foreign key constraints come into play. By specifying FOREIGN KEY (i_id) REFERENCES items(i_id) in the user_purchase table definition, we essentially give the RDBMS a rule to follow: entries with i_id values that are not contained in the items.i_id column are not acceptable. In other words, while a foreign key column implements the reference, a foreign key constraint enforces the referential integrity.
Note, however, that the above select wouldn't change, just because you defined a FK constraint. Thus, you don't use FK constraints, the RDBMS does, in order to protect your data.
Redundancies
...what if I want several columns? Why don't we use several foreign
keys for different columns of the same table?
Ask yourself: Why would you want that? If the two foreign keys are to serve the same purpose, the redundancy will eventually get you in trouble. Consider the following data:
user_purchase items
| id i_id name | | i_id name price |
| 55 10 chocolate bar | | 10 chocolate bar 3.42 |
| 70 10 chocolate bar | | 33 mobile phone 82.11 |
| 70 33 mobile phone | | 54 toothpaste 8.67 |
| 55 10 toothpaste | | 26 toy car 6.00 |
| 70 26 toy car |
What's wrong with this picture? Did user 55 buy two chocolate bars, or a chocolate bar and a toothpaste? This kind of ambiguity can lead to a lot of effort to keep data in-sync, which would be unnecessary if we just kept one of the foreign keys. In fact, why not drop the name column altogether, since it is implied by the relation.
Of course, we could resolve this by implementing a composite foreign key, by setting PRIMARY KEY(i_id,name) for the items table (or defining an extra UNIQUE(i_id,name) index, it doesn't realy matter) and then setting a FOREIGN KEY(i_id,name) REFERENCES items(i_id,name). This way, only (i_id,name) couples that exist in the items table would be valid for user_purchases. Apart from the fact that you would still have one foreign key, this approach is totally unnecessary, provided that the i_id column is already enough to identify an item (can't say the same for the name column...).
However, there's no rule against using multiple foreign keys to a table. In fact, there are circumstances that demand such an approach. Consider a person(id,name) table and a parent(person,father,mother) one, with the following data:
person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
Obviously, all three columns of the parent table are foreign keys to person. Not for the same relation, though, but for three different ones: Since a person's parents are persons too, the two corresponding columns must reference the same table person does. Note, however, that the three fields not only can but also have to refer different persons in the same parent row, since noone is his own parent and noone's father is his mother as well.
Foreign keys are used in joins. For instance, if you want to know the usernames that purchased a particular item, you would write:
select u.username
from items i
join user_purchase up on i.i_id = up.i_id
join user u on u.id = up.id
where i.name = "Some product name"
They may also be used by the database engine itself. It can detect if you create a row in user_purchase whose id or i_id column doesn't match anything in the referenced column in the other table.
You should not replicate the name column in the user_purchase table. The name is just an attribute of the item, it's not specific to any particular purchase. If you need to get the name of the item that was purchased, join with the items table.
Instead of reading so many links, just try to implement this in any simple project. I'm just explaining how we gonna use the above tables.
Suppose you 3 users in user table and 5 items in items table.
user table
id | username | password
1 abc 123
2 def 456
3 qwe 987
items table
i_id | name | price
1 item 1 6
2 item 2 8
3 item 3 11
4 item 4 3
5 item 5 14
your user_purchase table look like this
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
id INT(11) NOT NULL,
FOREIGN KEY (i_id) REFERENCES items(i_id),
FOREIGN KEY (id) REFERENCES user(id)
);
There is no need of item name again in this table. So I have removed.
i_id | id
1 1
1 2
2 2
3 3
In the above table we will get, user 1 has purchased item 1, user 2 has purchased item 1,item 2 and user 3 has purchased item 3.
This is how normalization works. You can use MySQL JOIN for getting user name and item details
SELECT B.user_name,C.name AS item_name,C.price
FROM user_purchase A
JOIN user B ON A.id = B.id
JOIN items C ON A.i_id = C.i_id
Here is foreign key use to join
A.id = B.id
A.i_id = C.i_id
You treet tables with foreign keys in php the same way, as if they had no foreign keys. Foreign keys are defined in the database and have (almost) nothing to do with php. The only thing you have to do in php is reacting to potential errors that can be returned by sql queries, which brake the foreign key constraint (typically DELETE queries).
And for your database schema, you should drop column "name" from "table user_purchase". It is redundat.
Just looking at the normalization/de-normalization point:
Normalization is a process of trying to remove redundancy in your database - in your example the name field in user_purchase is redundant - I can find out the name of the item by looking it up in the items table using i_id.
So if we were to look at normalizing user_purchase we'd probably remove the name field and use a JOIN to retrieve that when we needed it. This would, of course, also mean we don't need the second FOREIGN KEY reference to items.
De-normalization is basically going the opposite way - adding redundancy - usually done for performance reasons.
However, in your example you might also consider de-normalization for business reasons too. For example you might decide it is important to store the product name as it was when the user actually purchased it (rather than what it's called now) - just in case you need to be able to re-print an invoice for example. However even in this case you wouldn't want the FOREIGN KEY back to items (as it would "break" if the product was re-named).