how to write a trigger that forces a foreign key - mysql

I have a table name Service(product, loca, from_agent, to_agent).
product reference Product(pno)
from_agent references Customer(cno) U Driver(drno) U Airline(Ano)
to_agent references Customer(cno) U Driver(drno) U Airline(ano)
cno = Customer Number which is another table name "Customer"which has other details such as name, address etc
drno = Driver Number which is another table name "Driver" which has other details such as name, address etc
ano = Airline Number which is another table name "Airline"which has other details such as depport, depttime,arrtime etc..
would like to write a trigger that will force, the foreign key in the product table to be checked before any changes are made. Assuming local mapping transparency
Please help, I'm just learning about triggers and distribution database

Let's imagine a database for a shop: Items, Products, Brands (For exemple: "Yellow Peugeot bicycle with stripes", referenced as an item of "Peugeot bicycle", as a brand of "Peugeot".
CREATE TABLE IF NOT EXISTS `brands` (
`brandId` int(11) NOT NULL AUTO_INCREMENT,
`brandName` varchar(30) NOT NULL,
PRIMARY KEY (`brandId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
CREATE TABLE IF NOT EXISTS `items` (
`itemId` int(11) NOT NULL AUTO_INCREMENT,
`generalProductId` int(11) NOT NULL,
PRIMARY KEY (`itemId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `products` (
`productId` int(11) NOT NULL AUTO_INCREMENT,
`productName` varchar(200) NOT NULL,
`productBrand` int(11) NOT NULL,
PRIMARY KEY (`productId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
ALTER TABLE products ADD FOREIGN KEY(productBrand) REFERENCES brands(brandId) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE items ADD FOREIGN KEY(itemBrand) REFERENCES product(productBrand) ON DELETE RESTRICT ON UPDATE CASCADE;
So here, you have a foreign key constraint, which makes Items inherit the brand specified in Product, which inherits itself from Brands. In this case, if you modify Name for a special BrandId, child tables will have the akncowledge of that. ON DELETE RESTRICT means that you cannot break the chain and database will not allow you to delete an entry that is referenced elsewhere :)

Related

How can I delete rows from table connected with foreign key?

I have table Songs with columns(ID_Song, Title, ID_Artist, ID_Image, ID_Audio) where ID_Artist, ID_Image, ID_Audio are foreign key.
Table Artists with columns (ID_Artist, Name)
Table Images with columns (ID_Image,filename, extension, size)
Table Audios with columns (ID_Audio,filename, extension, size)
Columns songs.ID_Artist references Artists.ID_Artist, songs.ID_Image references Images.ID_Image and songs.ID_Audio references Audios.ID_Audio, so when I delete a row from table Songs I want the data connected with that row from other tables be deleted as well, but I can't because of the foreign key, is there a way to do it?
Table Songs
CREATE TABLE `songs` (
`ID_Song` int(11) NOT NULL AUTO_INCREMENT,
`SongTitle` varchar(100) NOT NULL,
`ID_Artist` int(11) NOT NULL,
`ID_Img` int(11) NOT NULL,
`ID_SongFile` int(11) NOT NULL,
`Approved` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`ID_Song`),
KEY `ID_Artist` (`ID_Artist`),
KEY `ID_SongFile` (`ID_SongFile`),
KEY `ID_Img` (`ID_Img`),
CONSTRAINT `songs_ibfk_1` FOREIGN KEY (`ID_Artist`) REFERENCES `artists` (`ID_Artist`) ON DELETE CASCADE,
CONSTRAINT `songs_ibfk_2` FOREIGN KEY (`ID_SongFile`) REFERENCES `files` (`ID_File`) ON DELETE CASCADE,
CONSTRAINT `songs_ibfk_3` FOREIGN KEY (`ID_Img`) REFERENCES `images` (`ID_Img`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Table Images
CREATE TABLE `images` (
`ID_Img` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`extension` varchar(10) NOT NULL,
`size` float NOT NULL,
PRIMARY KEY (`ID_Img`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
For the given schema, you need to fetch ID_SongFile and ID_Img before you delete a song. Assuming you want to delete the song with ID=123. In pure SQL it could be:
select ID_SongFile, ID_Img into #file_id, #img_id
from songs
where ID_Song = 123;
delete from songs where ID_Song = 123;
delete from images where ID_Img = #img_id;
delete from files where ID_File = #file_id;
Depending on your data logic, it might be better to "reverse" the relation. If files and images are only related to songs, and it's always a one-to-one relation, I would remove the ID_SongFile and ID_Img columns from the songs table and have a ID_Song column as foreign key in images and files tables. If you define those new FKs with ON DELETE CASCADE, you would just need to delete the song, and the related file and image will "disappear".
You could also just store all image and file information in the songs table. But IMHO having the columns image_name, image_extension, image_size, file_name, file_extension and file_size doesn't look very good. But there is nothing really wrong with that design.

How to properly organize historical data in the same table?

Main organization and problem
I'm working on a database of football matches, this db is organized in the following structure:
Country -> Competition -> Season -> Data
The basic matter of the question is that I'm not pretty sure that my database schema is correct.
Explain the data structure
The main "problem" is that each Data is grouped by a specific season, let's take in consideration the country England:
Country | Competition | Season |
England | Premier League | 2017/2018 |
England | Premier League | 2016/2017 |
England | Premier League | 2015/2016 |
England | Premier League | 2014/2015 |
England | Premier League | 2013/2014 |
as you can see the England have a competition named Premier League which is divided into 5 seasons.
Each competition is divided into rounds, a competition can be formed by a single round, but also by more rounds.
Each round could be divided into groups, this depends on the type of competition, some competitions aren't divided into groups.
Database structure
Based on my explaination of data relationship, I configured a database structure which have the following table:
country: contains all the countries informations available.
competition: contains all the competitions details.
competition_seasons: contains all the competition seasons.
competition_rounds: contains all the rounds available for the competition.
competition_groups: contains all the groups available for the competition.
league_ranking: contains all the ranking position of each team that partecipate on the specific competition.
The database schema is this (I does not have enough rep to display the image you need click on the link):
enter image description here
Database code
-- -----------------------------------------------------
-- Table `mydb`.`country`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`country` (
`id` INT NOT NULL,
`name` VARCHAR(255) NOT NULL,
`link` VARCHAR(255) NOT NULL,
`iso` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`competition`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`competition` (
`id` INT NOT NULL,
`country_id` INT NOT NULL,
`name` VARCHAR(255) NOT NULL,
`link` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`),
INDEX `id_idx` (`country_id` ASC),
CONSTRAINT `FK_country_competition_country_id`
FOREIGN KEY (`country_id`)
REFERENCES `mydb`.`country` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`competition_seasons`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`competition_seasons` (
`season_id` INT NOT NULL,
`competition_id` INT NOT NULL,
`name` VARCHAR(255) NOT NULL,
`create_at` DATETIME NULL,
`update_at` DATETIME NULL,
INDEX `competition_id_idx` (`competition_id` ASC),
PRIMARY KEY (`season_id`),
CONSTRAINT `FK_competition_competition_seasons_competition_id`
FOREIGN KEY (`competition_id`)
REFERENCES `mydb`.`competition` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`competition_groups`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`competition_groups` (
`group_id` INT NOT NULL,
`competition_id` INT NOT NULL,
`round_id` INT NOT NULL,
INDEX `group_id_idx` (`group_id` ASC),
INDEX `competition_id_idx` (`competition_id` ASC),
INDEX `round_id_idx` (`round_id` ASC),
CONSTRAINT `FK_group_competition_groups_group_id`
FOREIGN KEY (`group_id`)
REFERENCES `mydb`.`group` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_competition_competition_groups_competition_id`
FOREIGN KEY (`competition_id`)
REFERENCES `mydb`.`competition` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_round_competition_groups_round_id`
FOREIGN KEY (`round_id`)
REFERENCES `mydb`.`round` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`competition_rounds`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`competition_rounds` (
`competition_id` INT NOT NULL,
`round_id` INT NOT NULL,
INDEX `competition_id_idx` (`competition_id` ASC),
INDEX `round_id_idx` (`round_id` ASC),
CONSTRAINT `FK_competition_competition_rounds_competition_id`
FOREIGN KEY (`competition_id`)
REFERENCES `mydb`.`competition` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_round_competition_rounds_round_id`
FOREIGN KEY (`round_id`)
REFERENCES `mydb`.`round` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`league_ranking`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`league_ranking` (
`id` INT NOT NULL,
`position` INT NULL,
`team_id` INT NULL,
`season_id` INT NULL,
`round_id` INT NULL,
`competition_id` INT NULL,
`group_id` INT NULL,
`played_matches` INT NULL,
`wins` INT NULL,
`draws` INT NULL,
`losses` INT NULL,
`goals_for` INT NULL,
`goals_against` INT NULL,
`goals_difference` INT NULL,
`points` INT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_team_league_ranking_teamd_id`
FOREIGN KEY (`id`)
REFERENCES `mydb`.`team` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_round_league_ranking_round_id`
FOREIGN KEY (`id`)
REFERENCES `mydb`.`round` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_competition_league_ranking_competition_id`
FOREIGN KEY (`id`)
REFERENCES `mydb`.`competition` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_group_league_ranking_group_id`
FOREIGN KEY (`id`)
REFERENCES `mydb`.`group` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
is my database schema correct for store historical season?
Assuming
A competition is composed of 1 or more rounds,
A round is optionally composed of 1 or more groups.
Then I recommend
One table containing one row per 'competition'.
One table containing one row per 'round'. It should contain a competition_id that is a FK to competition.id.
One table containing one row per 'group'. It should contain a round_id that is a FK to round.id.
(Etc.)
Those are examples of doing "1:many" mappings. (Note "0 or more" and "optionally" are merely edge cases of "1:many", and do not require extra effort.)
I say "one table" because "vertical splitting" is rarely unnecessary. Simply put all the attributes for a "competition" in a single table. When some attribute (such as the 'rounds') is repeated, then it cannot be put in the same table.
(The table name competition_rounds, though descriptive, was confusing me.)
A related question... Are all the 'rounds' of a 'competition' played in a single country? I see country_id in competition; I wonder if it should be moved to rounds?
#1. First of all, I didn't understand the usages of "competition_round" table, here you defined this table with two column "competition_id" and "round_id". Anyway, you have defined "competition_id" and "round_id" in "leage_ranking" table, so, I suggest not to use the extra table to store the same data again.
#2. As you mentioned you want to store the data historically, then I am assuming there will be less transaction or not might be. So, I suggest you de-normalize the table. Because the end of the day you are going to analyze the data and going to perform lots of data mining on historical data to provide appropriate business expectations.
#3. Other than this it seems a good data model, as per my experience.
Refer this link for understanding the database design patterns

Problems setting one-to-many relationships on PHPMyAdmin

I am having a problem setting my one-to-many relationships on PHPMyAdmin
Here is tbl_books
book_id (primary key)
bookcat_id_fk (foreign key 'on update restrict, on delete restrict')
bookname
bookdesc
Here is tbl_bookcat
bookcat_id (primary key)
bookcat_name
The relationship between the two should be that there is ONE category to MANY books, so a one-to-many relationship.
The problem that am getting would be that I am getting the error: Duplicate entry '1' for key bookcat_id_fk
This means that I am unable to assign more books to the same category because of this, so my one-to-many relationship is not working. I have searched but I could find the answer I was wondering if you could help me out.
Thanks.
I suspect your key definition bookcat_id_fk is UNIQUE, but without seeing the full dump don't know for sure. Anyway, I believe this is what you're trying to achieve:
CREATE TABLE IF NOT EXISTS `tbl_bookcat` (
`bookcat_id` int(11) NOT NULL,
`bookcat_name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `tbl_books` (
`book_id` int(11) NOT NULL,
`bookcat_id_fk` int(11) NOT NULL,
`bookname` varchar(255) NOT NULL,
`bookdesc` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `tbl_bookcat`
ADD PRIMARY KEY (`bookcat_id`);
ALTER TABLE `tbl_books`
ADD PRIMARY KEY (`book_id`),
ADD KEY `bookcat_id_fk` (`bookcat_id_fk`);
ALTER TABLE `tbl_bookcat`
MODIFY `bookcat_id` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `tbl_books`
MODIFY `book_id` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `tbl_books`
ADD CONSTRAINT `tbl_books_ibfk_1` FOREIGN KEY (`bookcat_id_fk`) REFERENCES `tbl_bookcat` (`bookcat_id`);

Need some assistance in verifying a database logical schema to Third Normal Form

This was originally going to be an "update" on the logical schema presented in another question here: Getting ERROR 1701, ERROR 1452 and ERROR 1305 errors in MySQL - Need some expertise...
I think I have successfully verified this schema to 1st and 2nd Normal Form, but am unsure if this meets 3rd Normal Form. Here is the model in question:
And here is the associated code (note: for some reason I cannot recreate 1:1 relationships in the sql code as illustrated in the logical model above):
-- database_schema.sql.
-- This sql script creates the structure.
-- of the rugby club database.
DROP DATABASE IF EXISTS database_rugby;
CREATE DATABASE database_rugby;
USE database_rugby;
-- Create the "person" table.
--
-- This table has one:one relationships
-- with the parent, coach and player
-- tables.
DROP TABLE IF EXISTS `person` ;
CREATE TABLE `person` (
`personID` INT(5) NOT NULL AUTO_INCREMENT ,
`firstName` VARCHAR(50) NOT NULL ,
`lastName` VARCHAR(50) NOT NULL ,
`dateOfBirth` DATE NOT NULL ,
`streetAddress` VARCHAR(150) NOT NULL ,
`suburbAddress` VARCHAR(150) NULL DEFAULT NULL ,
`cityAddress` VARCHAR(150) NOT NULL ,
`photo` BLOB NULL DEFAULT NULL ,
PRIMARY KEY (`personID`))
ENGINE = InnoDB;
-- Create the "parent" table.
DROP TABLE IF EXISTS `parent` ;
CREATE TABLE `parent` (
`parentID` INT(5) NOT NULL ,
`personID` INT(5) NOT NULL ,
PRIMARY KEY (`parentID`, `personID`),
FOREIGN KEY (`personID`) REFERENCES `person` (`personID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "school" table.
DROP TABLE IF EXISTS `school` ;
CREATE TABLE `school` (
`schoolID` INT(5) NOT NULL AUTO_INCREMENT ,
`schoolName` VARCHAR(100) NOT NULL ,
PRIMARY KEY (`schoolID`))
ENGINE = InnoDB;
-- Create the "player" table.
--
-- Inherits fields from the "person"
-- and "school" tables.
DROP TABLE IF EXISTS `player` ;
CREATE TABLE `player` (
`playerID` INT(5) NOT NULL ,
`personID` INT(5) NOT NULL ,
`schoolID` INT(5) NOT NULL ,
PRIMARY KEY (`playerID`, `personID`),
FOREIGN KEY (`personID`)
REFERENCES `person` (`personID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`schoolID`)
REFERENCES `school` (`schoolID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "coach" table.
DROP TABLE IF EXISTS `coach`;
CREATE TABLE `coach`(
`coachID` INT(5) NOT NULL ,
`dateBeganCoaching` DATE NOT NULL ,
`personID` INT(5) NOT NULL ,
PRIMARY KEY (`coachID`, `personID`),
FOREIGN KEY (`personID`)
REFERENCES `person` (`personID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "family" table.
--
-- This is a linking table
-- that describes the many:many
-- relationship between "parent"
-- and "player" tables.
DROP TABLE IF EXISTS `family` ;
CREATE TABLE `family` (
`parentID` INT(5) NOT NULL ,
`playerID` INT(5) NOT NULL ,
FOREIGN KEY (`playerID` )
REFERENCES `player` (`playerID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`parentID`)
REFERENCES `parent` (`parentID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- Create the "grade" table.
DROP TABLE IF EXISTS `grade`;
CREATE TABLE `grade`(
`gradeID` INT(5) NOT NULL AUTO_INCREMENT ,
`gradeName` VARCHAR(50) NOT NULL ,
`minWeight` INT(3) NOT NULL ,
`maxWeight` INT(3) NOT NULL ,
`minAge` INT(3) NOT NULL ,
`maxAge` INT(3) NOT NULL ,
`ballSize` INT(1) NOT NULL ,
PRIMARY KEY (`gradeID`) )
ENGINE = InnoDB;
-- Create the "coachQualification" table.
DROP TABLE IF EXISTS `coachQualification` ;
CREATE TABLE `coachQualification` (
`qualID` INT(5) NOT NULL AUTO_INCREMENT ,
`qualName` CHAR(5) NOT NULL ,
`gradeID` INT(5) NOT NULL ,
PRIMARY KEY (`qualID`) ,
FOREIGN KEY (`gradeID`)
REFERENCES `grade` (`gradeID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "homePhone" table.
DROP TABLE IF EXISTS `homePhone` ;
CREATE TABLE `homePhone` (
`homePhoneID` INT(5) NOT NULL AUTO_INCREMENT ,
`homeNumber` CHAR(9) NOT NULL ,
PRIMARY KEY (`homePhoneID`))
ENGINE = InnoDB;
-- Create the "mobilePhone" table.
DROP TABLE IF EXISTS `mobilePhone` ;
CREATE TABLE `mobilePhone` (
`mobilePhoneID` INT(5) NOT NULL AUTO_INCREMENT ,
`mobileNumber` CHAR(10) NULL DEFAULT NULL ,
PRIMARY KEY (`mobilePhoneID`))
ENGINE = InnoDB;
-- Create the "emailAddress" table.
DROP TABLE IF EXISTS `emailAddress` ;
CREATE TABLE `emailAddress` (
`emailAddressID` INT(5) NOT NULL AUTO_INCREMENT ,
`emailAddress` CHAR(10) NULL DEFAULT NULL ,
PRIMARY KEY (`emailAddressID`))
ENGINE = InnoDB;
-- Create the "Contact" table
--
-- This is a linking table
-- that describes the many:many
-- relationships between "person"
-- and the "homePhone", "mobilePhone",
-- and "emailAddress" tables.
DROP TABLE IF EXISTS `contact` ;
CREATE TABLE `contact` (
`personID` INT(5) NOT NULL ,
`homePhoneID` INT(5) NOT NULL ,
`mobilePhoneID` INT(5) NULL DEFAULT NULL ,
`emailAddressID` INT(5) NULL DEFAULT NULL ,
FOREIGN KEY (`personID` )
REFERENCES `person` (`personID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`homePhoneID`)
REFERENCES `homePhone` (`homePhoneID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`mobilePhoneID`)
REFERENCES `mobilePhone` (`mobilePhoneID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`emailAddressID`)
REFERENCES `emailAddress` (`emailAddressID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "qualificationSet" table.
--
-- This is a linking table
-- that describes the many:many
-- relationship between "coach"
-- and "coachQualification" tables.
DROP TABLE IF EXISTS `qualificationSet` ;
CREATE TABLE `qualificationSet` (
`coachID` INT(5) NOT NULL ,
`qualID` INT(5) NOT NULL ,
FOREIGN KEY (`coachID`)
REFERENCES `coach` (`coachID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`qualID`)
REFERENCES `coachQualification` (`qualID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "team" table.
DROP TABLE IF EXISTS `team` ;
CREATE TABLE `team` (
`teamID` INT(5) NOT NULL AUTO_INCREMENT ,
`teamName` VARCHAR(50) NOT NULL ,
`teamYear` INT(2) NOT NULL ,
`gradeID` INT(5) NOT NULL ,
PRIMARY KEY (`teamID`) ,
FOREIGN KEY (`gradeID`)
REFERENCES `grade` (`gradeID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "teamAllocation" table
--
-- this is a linking table for a
-- many:many relationship between
-- team and player tables.
DROP TABLE IF EXISTS `teamAllocation` ;
CREATE TABLE `teamAllocation` (
`teamID` INT(5) NOT NULL ,
`playerID` INT(5) NOT NULL ,
FOREIGN KEY (`teamID` )
REFERENCES `team` (`teamID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`playerID`)
REFERENCES `player` (`playerID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "teamCoachAllocation" table.
--
-- This is a linking table
-- that describes the many:many
-- relationship between "coach"
-- and "team" tables.
DROP TABLE IF EXISTS `teamCoachAllocation` ;
CREATE TABLE `teamCoachAllocation` (
`coachID` INT(5) NOT NULL ,
`teamID` INT(5) NOT NULL ,
FOREIGN KEY (`coachID`)
REFERENCES `coach` (`coachID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`teamID`)
REFERENCES `team` (`teamID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
From these links below:
http://en.wikipedia.org/wiki/First_normal_form
http://en.wikipedia.org/wiki/Second_normal_form
http://en.wikipedia.org/wiki/Third_normal_form
This is my understanding of Normalisation to 3NF:
First normal form means to not allow repeating values
Second normal form means 1NF and attributes are dependant on whole primary key and not part of a primary key (I think of this as partitioning tables if values in that table need to relate to eachother in some way and have comparisons made).
Third normal form means 2NF and no transistive values (e.g if x = y and y = z, x = z)
Putting that knowledge from theory into practice is quite hard for me, especially translating that "practise" into working, normalised MySQL code. If someone is able to help me go through the model and give me some pointers about normalising the model to 3NF, I would appreciate it very much.
Thanks in advance!
I think this isn't in 3NF, around the contact table. If I'm wrong this is still a bad way of storing the data and should probably be changed.
Sorry if this is a little confused...
It is entirely possible to have the following structure in your contact table as the entire table is the primary key:
+----------+-------------+---------------+---------+
| personid | homephoneid | mobilephoneid | emailid |
+----------+-------------+---------------+---------+
| 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 2 |
| 1 | 1 | 2 | 3 |
+----------+-------------+---------------+---------+
As you can see both homephoneid and mobilephoneid are duplicated so updating the table homephone will result 3 updates to contact.
I disagree with the data-model as you require a person to have a homehone I don't have one, only a mobile. In this situation, when creating a new person you have to also create a new contact and a new homephone.
As contact is just a primary key and a primary key value cannot be null, you also require the creation of a mobilephone and an emailaddress, which means that person is dependent on emailaddress.
As emailaddress is dependent on contact, which in turn is dependent on person you've created a circular dependency, which breaks 3NF.
As I see it you have a two options if you want to ensure that people have to have a home phone number:
If you only want a person to have one homephone then add this
into the person table. It's unique contact level information and
should be stored there.
If you want to enable people to have multiple home phone numbers -
remembering that multiple people can use the same phone number - but
don't care about mobiles then you need to create a table
personhomephones, say, with the primary key personid,
homephoneid and not put homephoneid in the contact table.
Personally I wouldn't do either of these. I wouldn't ensure that someone has to have a home phone number but instead a primary phone number, where you don't care what type it is. I would allow people to add different methods of contact but allow these not to exist
This would require the following structure:
person - add primaryPhoneID
primaryphone ( primaryphoneID, phonenumber) - PK primaryphoneID
Then for the contact methods that are allowed to not exist:
contactType ( contactTypeID, contactType ) - PK contactTypeID
contact ( contactID, contactTypeID, value ) - PK contactID, contactTypeID
personContact ( personID, contactID, contactTypeID ) - PK everything
Whilst this may result in duplication between contact and primaryphone they are distinct bits of data and I think this is fine. If you're insistent on not allowing any duplication at all you'd have to separate out the phones from the other methods of contact, which makes the model more complicated:
phonetype ( phoneTypeId, phoneType )
phone ( phoneID, phoneTypeID, phonenumber) - PK phoneID, phoneTypeID
contactPhone ( personID, phoneTypeID, phoneID ) - PK everything
There is an algorithm to eventually decompose each relation in your schema in order to get an equivalent schema in 3NF. Google is good for that!!
To get tips about your schema design you should at least describe the context and the functional constraints about the entities you need to represent.

mysql innodb basic design for joomla component

I have four entities:
person
center
activity
address
So my idea is:
A person may have an associated address.
A center may have an associated address.
An activity may have an associated address.
Is this mysql design correct for a joomla component?
CREATE TABLE `#__person` (
`id` int(10) NOT NULL AUTO_INCREMENT,
other fields...
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `#__center` (
`id` int(10) NOT NULL AUTO_INCREMENT,
other fields...
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `#__activity` (
`id` int(10) NOT NULL AUTO_INCREMENT,
other fields...
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `#__address` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`line1` varchar(30),
`line2` varchar(30),
`locality` varchar(10),
`region` varchar(10),
`country` varchar(10),
`postcode` varchar(10),
`person_id` int(10),
`center_id` int(10),
`activity_id` int(10),
PRIMARY KEY (id),
FOREIGN KEY `person_id` REFERENCES `#__person` (id) ON DELETE CASCADE,
FOREIGN KEY `center_id` REFERENCES `#__center` (id) ON DELETE CASCADE,
FOREIGN KEY `activity_id` REFERENCES `#__activity` (id) ON DELETE CASCADE,
other fields...
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
So i.e:
If I delete a person, automatically his/her corresponding address will be deleted?
And if I delete an address, what will happen to their references? (hope nothing)
What happens if the same address is an address for a center and for an activity?
Are the foreign keys in the correct table or should i put an address_id field in person,center and activity?
I'm a bit confused about my design.
Thank you for your suggestions.
Instead of placing an id for person, center and activity into the address table, I would suggest placing an address_id into each of the other tables (person, center, and activity). Then, you could reuse the same address across the other tables and in different combinations of person, center, and activity.
And about cascade, I think the MySQL Reference manual explains it well:
CASCADE: Delete or update the row from the parent table, and
automatically delete or update the matching rows in the child table.
Both ON DELETE CASCADE and ON UPDATE CASCADE are supported. Between
two tables, do not define several ON UPDATE CASCADE clauses that act
on the same column in the parent table or in the child table.
So if you did change address_id to be in each of the other tables and then you applied the foreign key constraint
FOREIGN KEY `address_id` REFERENCES `#__address` (id) ON DELETE CASCADE
then when you deleted the row in the address table (the one WITHOUT the foreign key constraint), the matching rows in either person, center, or activity (where the foreign keys are defined), would be deleted. BUT, I am guessing that this might not be what you want, because you said a person, center and activity "may" have an address. So if you deleted the address, you do not necessarily want to delete the person, center or activity that was using that address. If that is true, then I would change your foreign key constraint in each of the 3 tables to:
FOREIGN KEY `address_id` REFERENCES `#__address` (id) ON DELETE SET NULL