Databases normalization in 2NF - mysql

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 |
-------------------------- ---------------------------
|____________|___________| |___________|_____________|

Related

One to many relationship MYSQL

I'm new to mysql and am trying to link two tables and am not sure how, i have a products table with a list of products in a restaurant, the column in this table are
ID(primary key)
name
price
The other table is called extras, this table contains extra things that you can add to your order but are optional, for when buying chicken you have an option of spicy and non spicy,
Some products have more than one extras, for instance a product can have the option of choosing three extras.
The extras table at the moment only has
ID(primary key)
name
not sure how to link the two or where to put foreign constraints.
UPDATE
Same extra may also belong to numerous products
A joining/linking table usually uses many-to-many relationships by joining the 2 parent tables/primary keys to allow many products to have many extras or no extras at all.
so for example:
eg:
Product IDs (primary keys) are: 1, 2, 3
Product names are: chicken wings, chicken breast, chicken fillet
Extras IDs (primary keys) are: 1, 2, 3
Extras names are: mild, medium, hot
Wings, breasts and fillet have the option of all three of the extras, so the product_extras table would end up looking something like this:
product_extras_id | product_id | extras_id
------------------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 2
6 | 2 | 3
7 | 3 | 1
8 | 3 | 2
9 | 3 | 3
With products having many extras and extras applying to many products this is actually a many to many relationship.
create table products(ID int auto_increment Primary Key,
Name varchar(50),
Price decimal(6,2));
create table extras(ID int auto_increment Primary Key,
Name varchar(50));
create table product_extras(Product int Not Null,
Extra int Not Null,
FOREIGN KEY(Product) References products(ID) ON DELETE CASCADE,
FOREIGN KEY(Extra) References extras(ID) ON DELETE CASCADE);
Something akin to this should work for you, though you may want to change the datatypes based off preference and what data actually needs to go in there.
In your case one product may have many extras(1 to many) and many products may be having same extra thing(many to 1). Thus, this is a many to many relationship and for such relations we need 3 tables.
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
price DECIMAL(10.2)
);
CREATE TABLE extras (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
CREATE TABLE products_extras (
id INT PRIMARY KEY AUTO_INCREMENT,
pro_id INT,
FOREIGN KEY(pro_id) REFERENCES products(id),
ext_id INT,
FOREIGN KEY(ext_id) REFERENCES extras(id)
);

Mysql create table with two foreign keys referencing primary key

I have two mysql tables. The first one is created using the following code:
create table project(
project_id int not null auto_increment,
project_name varchar(30)
primary key(project_id));
The second table:
create table matches(
match_id int not null auto_increment,
match_name varchar(30),
project_id int(4) foreign key (project_id) references projects(project_id));
Both these commands works fine. I want to add the project_name column from the first table to the second table. I tried using
alter table projects drop primary key, add primary key(project_id, project_name);
and then
alter table matches add column project_name varchar(30), add foreign key (project_name) references projects(project_name);
But got the following error:
ERROR 1005 (HY000): Can't create table 'matches.#sql-55e_311' (errno: 150)
How do i include both the columns from the first table into the second table.
The current structure of my second table is as follows:
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| match_id | int(11) | NO | PRI | NULL | auto_increment |
| match_name | varchar(30) | YES | | NULL | |
| project_id | int(4) | NO | MUL | NULL | |
+------------+-------------+------+-----+---------+----------------+
I want to add the project_name as the fourth column in my second table.
To use a compound Primary Key as Foreign Key, you'll have to add the
same number of columns (that compose the PK) with same datatypes to
the child table and then use the combination of these columns in the
FOREIGN KEY definition.
see related post here https://stackoverflow.com/a/10566463/4904726
so try this way
alter table matches add foreign key (project_id, project_name) references projects(project_id, project_name);
Do you understand what a FK constraint says? It says a list of values for some columns in a table must appear as a list of values for some columns forming a (declared) PK or UNIQUE NOT NULL in the referenced table. So what you are writing doesn't make sense. If you wanted a PK (project_id, project_name) then that should also be the form of your FK.
But (project_id, project_name) is not two 1-column PKs, it is one 2-column PK, and it is probably not what you want since presumably in projects it isn't just pairs that are unique it is each column. Presumably you want two 1-column PKs and two one-column FKs, one referencing each PK.
If projects project_id was NOT NULL you could write:
alter table projects add primary key(project_name);
alter table matches add column project_name varchar(30),
add foreign key (project_name) references projects(project_name);
But if project_name can be NULL in projects then you cannot make it a PK and you cannot sensibly have a FK to it. You can make it UNIQUE. Unfortunately MySQL lets you write such a FK declaration to a non-NULL UNIQUE column while it also tells you not to do it:
The handling of foreign key references to non-unique keys or keys that contain NULL values is not well defined for operations such as UPDATE or DELETE CASCADE. You are advised to use foreign keys that reference only keys that are both UNIQUE (or PRIMARY) and NOT NULL.
So if you want projects project_name to be nullable then should declare it UNIQUE but you should enforce the logical matches project_name match with a trigger.

Implementing Tree Structure In MySQL Database

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...

MySQL Grouping rows by a shared ID

Say I have
ID | PRODUCT
1 | Apples
1 | Oranges
1 | Bananas
2 | Walnuts
2 | Almonds
3 | Steak
3 | Chicken
Is this possible to have this type of setup in MySQL? I created a test table, and made an ID column with primary index and auto incrementing. When I try to insert a couple rows all having the same ID, mysql returns an error.
Is this possible to do in mysql?
How did the duplicate records (ID) INSERTED when you set ID as Primary Key? Basically, it will not. Primary Keys are UNIQUE. If you want records to be like that, make another column which served as your primary key
CREATE TABLE sampleTable
(
ID INT NOT NULL AUTO_INCREMENT,
GROUP_ID INT NOT NULL,
PRODUCT VARCHAR(25),
CONSTRAINT pk_name PRIMARY KEY (ID),
CONSTRAINT uq_name UNIQUE (GROUP_ID, PRODUCT)
)
a UNIQUE constraint was added so to avoid duplicated rows.
That is possible, but it is not normalized as you have a repeating primary key. Primary keys must be unique, which means 1 can only occur once. If you have custom ID's for each product, then either use a compound primary key (id, product) or a surrogate key. A surrogate key would be an auto incrementing column that uniquely identifies the row. Your table would then look like this:
CREATE TABLE fruits (
auto_id int AUTO_INCREMENT PRIMARY KEY,
id int,
product varchar(15))
You mustn't create a primary key for the ID column, as this implies that it's unique.
Just take a normal index for your example.
On the other hand, in most cases, it makes sense to have a primary key, so I'd recommend adding a 3rd row (GENRE?) with a normal INDEX on it and leaving the primary key as it is.
When inserting data, just insert the GENRE and the PRODUCT, the ID will be automatically filled.

Three Primary Keys relating three different tables

I have the following tables category, Restaurant, and menu.
A restaurant can have more than one menu, and a restaurant can also have more than one category. Each menu obviously has some number of catagories, and each catagory can be a part of a number of menus.
Can I create a table that looks like this, and has 3 primary keys?
Category ID | Restaurant ID | Menu ID
1 (Appetizer) | 1 Chile's | 2 Dinner Menu
2 (Entree) | 1 Chile's | 2 Dinner Menu
3 (Dessert) | 1Chile's | 2 Dinner Menu
1 | 67 McDonalds | 3 Lunch Menu
1
Yes, you can make a primary key of the tuple (category_id, restaurant_id, menu_type_id). Better even, make a normal, integral primary key, and add another index on that tuple with uniqueness constraint. It's always good to have a fast, simple primary key, but you can certainly enforce uniqueness of the triple:
CREATE UNIQUE INDEX menu_index
ON menus (category_id, restaurant_id, menu_type_id)
Or you can define the index right in the table creation:
CREATE TABLE menus (menu_id INT AUTO_INCREMENT PRIMARY KEY,
category_id INT,
restaurant_id INT,
menu_type_id INT,
FOREIGN KEY (category_id) REFERENCES categories(category_id),
FOREIGN KEY (restaurant_id) REFERENCES restaurants(restaurant_id),
FOREIGN KEY (menu_type_id) REFERENCES menu_types(menu_type_id),
UNIQUE INDEX (category_id, restaurant_id, menu_type_id)
) ENGINE=InnoDB;