I have an entity which has NOT NULL requirements based on the group it belongs to. For instance...
There are three types of churches: Buddhist, Muslim, and Christian.
All churches have some common required properties, however, each type of church has additional required properties.
All people have some common required properties, however, they have additional required properties based on the church type they belong to.
People must belong to one and only one church, however, may change their church to any other one of any religion provided that the above rules are met. The "type" of person they are is based on the church type they belong to.
How should entities who's required properties are based on the group which the entity belongs to be modeled? Or given my scenario, how should churches and people be modeled?
This is currently what I am doing, but it does not seem right. For instance, a person can be added before they become a Buddhist, Muslim, or Christian which breaks the rules. Also, a person or church can be more than one type which also breaks the rules.
-- MySQL Script generated by MySQL Workbench
-- 02/10/17 21:41:31
-- Model: New Model Version: 1.0
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`churches`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`churches` (
`idchurches` INT NOT NULL,
`name` VARCHAR(45) NOT NULL,
`address` VARCHAR(45) NOT NULL,
`members` INT NOT NULL,
PRIMARY KEY (`idchurches`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`churches_buddhist`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`churches_buddhist` (
`churches_idchurches` INT NOT NULL,
`number_of_buddas_in_church` VARCHAR(45) NOT NULL,
PRIMARY KEY (`churches_idchurches`),
CONSTRAINT `fk_churches_buddhist_churches`
FOREIGN KEY (`churches_idchurches`)
REFERENCES `mydb`.`churches` (`idchurches`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`churches_muslim`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`churches_muslim` (
`churches_idchurches` INT NOT NULL,
`savior` VARCHAR(45) NOT NULL,
PRIMARY KEY (`churches_idchurches`),
CONSTRAINT `fk_churches_muslim_churches1`
FOREIGN KEY (`churches_idchurches`)
REFERENCES `mydb`.`churches` (`idchurches`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`churches_christian`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`churches_christian` (
`churches_idchurches` INT NOT NULL,
`savior` VARCHAR(45) NOT NULL,
`number_of_crosses_in_church` INT NOT NULL,
PRIMARY KEY (`churches_idchurches`),
CONSTRAINT `fk_churches_christian_churches1`
FOREIGN KEY (`churches_idchurches`)
REFERENCES `mydb`.`churches` (`idchurches`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`people`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`people` (
`idpeople` INT NOT NULL,
`name` VARCHAR(45) NOT NULL,
`age` TINYINT NOT NULL,
`race` VARCHAR(45) NOT NULL,
`gender` VARCHAR(45) NOT NULL,
`favoriteVegitable` VARCHAR(45) NOT NULL,
PRIMARY KEY (`idpeople`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`buddhists`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`buddhists` (
`people_idpeople` INT NOT NULL,
`WidthOfBelly` BIGINT NOT NULL,
`LevelOfCconsciousness` INT NOT NULL,
`churches_buddhist_churches_idchurches` INT NOT NULL,
PRIMARY KEY (`people_idpeople`),
INDEX `fk_buddhists_churches_buddhist1_idx` (`churches_buddhist_churches_idchurches` ASC),
CONSTRAINT `fk_buddhists_people1`
FOREIGN KEY (`people_idpeople`)
REFERENCES `mydb`.`people` (`idpeople`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_buddhists_churches_buddhist1`
FOREIGN KEY (`churches_buddhist_churches_idchurches`)
REFERENCES `mydb`.`churches_buddhist` (`churches_idchurches`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`muslims`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`muslims` (
`people_idpeople` INT NOT NULL,
`DaysOffTakenForRamadan` INT NOT NULL,
`favoriteMeat` VARCHAR(45) NOT NULL,
`churches_muslim_churches_idchurches` INT NOT NULL,
PRIMARY KEY (`people_idpeople`),
INDEX `fk_muslims_churches_muslim1_idx` (`churches_muslim_churches_idchurches` ASC),
CONSTRAINT `fk_muslims_people1`
FOREIGN KEY (`people_idpeople`)
REFERENCES `mydb`.`people` (`idpeople`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_muslims_churches_muslim1`
FOREIGN KEY (`churches_muslim_churches_idchurches`)
REFERENCES `mydb`.`churches_muslim` (`churches_idchurches`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`christians`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`christians` (
`people_idpeople` INT NOT NULL,
`ChristmasPresentsReceived` INT NOT NULL,
`HolyMarysSaidPerDay` INT NOT NULL,
`favoriteMeat` VARCHAR(45) NOT NULL,
`FavoritePork` VARCHAR(45) NOT NULL,
`churches_christian_churches_idchurches` INT NOT NULL,
PRIMARY KEY (`people_idpeople`),
INDEX `fk_christians_churches_christian1_idx` (`churches_christian_churches_idchurches` ASC),
CONSTRAINT `fk_christians_people1`
FOREIGN KEY (`people_idpeople`)
REFERENCES `mydb`.`people` (`idpeople`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_christians_churches_christian1`
FOREIGN KEY (`churches_christian_churches_idchurches`)
REFERENCES `mydb`.`churches_christian` (`churches_idchurches`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
One idiom declaratively enforcing disjoint subtypes:
add type discriminator/tag column religion_type to parent and child tables
add superkey UNIQUE NOT NULL (id, religion_type)to parent tables
add FOREIGN (super) KEY (id, religion_type) to child tables, referencing parents
add constraint CHECK( religion_type = 'religion' ) or constant computed column with value religion to child tables
This still doesn't enforce that every parent is a child. From this answer:
One needs triggers to reasonably constrain SQL databases. One uses idioms to get what declarative constraints one can.
Just find the straightforward predicate for each relevant application relationship and give it a table. Here, that's parent and child tables. The constraints follow from the predicates and possible situtations. Declare them to prevent impossible updates. Whenever values in some columns must appear in other columns we declare a FK. You don't have to think about a special case for subtyped entity ids. Certain ids will end up in certain tables because certain things are true of them. It is ultimately their satisfying different predicates that makes things of different "types", rather than vice versa.
Related
So this is my code, I cannot proceed because I am always getting that foreign key constraint error. I have checked the data type they are consistent. Where am I going wrong?. All the problem persists where foreign keys are required. i have just posted two tables here.
-- -----------------------------------------------------
-- Table `44376936`.`AccountType`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `44376936`.`AccountType` ;
CREATE TABLE IF NOT EXISTS `44376936`.`AccountType` (
`AccountTypeID` float NOT NULL,
`AccountTypeName` VARCHAR(45) NULL,
`AccountTypeDesc` VARCHAR(45) NULL,
`AccountTypeInterestRate` FLOAT NULL,
`AccountTypeServiceFee` FLOAT NULL,
PRIMARY KEY (`AccountTypeID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `44376936`.`Account`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `44376936`.`Account` ;
CREATE TABLE IF NOT EXISTS `44376936`.`Account` (
`AccountBSB` INT NOT NULL,
`AccountNumber` INT NOT NULL,
`AccountCurrentBalance` FLOAT NULL,
`AccountType_AccountTypeID` Float NOT NULL,
PRIMARY KEY (`AccountBSB`, `AccountNumber`, `AccountType_AccountTypeID`),
INDEX `fk_Account_AccountType_idx` (`AccountType_AccountTypeID` ASC),
CONSTRAINT `fk_Account_AccountType`
FOREIGN KEY (`AccountType_AccountTypeID`)
REFERENCES `44376936`.`AccountType` (`AccountTypeID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
I can reproduce
It comes from this instruction :
REFERENCES `44376936`.`AccountType` (`AccountTypeID`)
and the problem is the database name, probably because it begins with a number and not a letter.
This works :
REFERENCES `AccountType` (`AccountTypeID`)
So get rid of the database name. If you are running this without being on the 44376936 database, execute this instruction at the beginning of your script :
USE `44376936`;
Rextester example
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
I have a supertype table called "vehicles". I also have three subtype tables called "airplanes", "automobiles", and "bicycles", and one and only one of these subtype tables must be linked to the vehicles supertype table (or in other words, must use the vehicles primary key ID as its primary key ID).
How should this be modeled to enforce this behavior?
EDIT Proposed schema recommended by Mike Brant.
-- MySQL Script generated by MySQL Workbench
-- 05/25/16 09:20:17
-- Model: New Model Version: 1.0
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`vehicle_types`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`vehicle_types` (
`type` CHAR(8) NOT NULL,
PRIMARY KEY (`type`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`vehicles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`vehicles` (
`idvehicles` INT NOT NULL AUTO_INCREMENT,
`type` CHAR(8) NOT NULL,
`data` VARCHAR(45) NULL,
PRIMARY KEY (`idvehicles`),
INDEX `fk_vehicles_vehicle_types_idx` (`type` ASC),
CONSTRAINT `fk_vehicles_vehicle_types`
FOREIGN KEY (`type`)
REFERENCES `mydb`.`vehicle_types` (`type`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`airplanes`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`airplanes` (
`vehicles_idvehicles` INT NOT NULL,
`data_for_airplanes` VARCHAR(45) NULL,
PRIMARY KEY (`vehicles_idvehicles`),
CONSTRAINT `fk_airplanes_vehicles1`
FOREIGN KEY (`vehicles_idvehicles`)
REFERENCES `mydb`.`vehicles` (`idvehicles`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`automobiles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`automobiles` (
`vehicles_idvehicles` INT NOT NULL,
`data_for_automobiles` VARCHAR(45) NULL,
PRIMARY KEY (`vehicles_idvehicles`),
CONSTRAINT `fk_automobiles_vehicles1`
FOREIGN KEY (`vehicles_idvehicles`)
REFERENCES `mydb`.`vehicles` (`idvehicles`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`bicycles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`bicycles` (
`vehicles_idvehicles` INT NOT NULL,
`data_for_bicycles` VARCHAR(45) NULL,
PRIMARY KEY (`vehicles_idvehicles`),
CONSTRAINT `fk_bicycles_vehicles1`
FOREIGN KEY (`vehicles_idvehicles`)
REFERENCES `mydb`.`vehicles` (`idvehicles`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
I think inserting in vehicles and any of other sub types should be simultaneously. Therefore you can get the vehicle ID and put as new sub-type PK ID. If you have all information at the same time you can create a transcation and insert the vehicle record first then the sub-type record. Then commit your transscation otherwise rollback it. IF you want to know which record belongs to which sub-type table record you can add a column to your vehicle table that for example can have 3 different values such as 0,1,2 that shows which record belongs to which sub-table. Enum in java can be used in something like that for more clarification
Looking at your proposed schema, I see no reason whatsoever for you to have separate tables for each vehicle type, or even a separate table to contain the allowable vehicle types. Your vehicle-specific tables are all basically the same thing meaning you can easily collapse into a single table, and you can use ENUM field to enforce allowable vehicle types.
Why not just have a single vehicles table like the following?
CREATE TABLE IF NOT EXISTS `mydb`.`vehicles` (
`idvehicles` INT NOT NULL AUTO_INCREMENT,
`type` ENUM('airplane', 'automobile', 'bicycle') NOT NULL,
`data` VARCHAR(45) NULL,
PRIMARY KEY (`idvehicles`),
INDEX `fk_vehicles_vehicle_types_idx` (`type` ASC))
ENGINE = InnoDB;
This approach totally eliminates 4 of your 5 tables, meaning you no longer have to consider using joins, foreign key constraints, etc. when performing CRUD operations against these records.
To enforce exclusive subtypes, copy the type indicator into each of the subtype tables and use composite foreign key constraints:
CREATE TABLE IF NOT EXISTS `mydb`.`airplanes` (
`vehicles_idvehicles` INT NOT NULL,
`type` CHAR(8) NOT NULL,
`data_for_airplanes` VARCHAR(45) NULL,
PRIMARY KEY (`vehicles_idvehicles`),
CONSTRAINT `fk_airplanes_vehicles1`
FOREIGN KEY (`vehicles_idvehicles`, `type`)
REFERENCES `mydb`.`vehicles` (`idvehicles`, `type`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Next you need to restrict the value of type in each table. Unfortunately, MySQL doesn't support check constraints, so you would need to use triggers:
DELIMITER ;;
CREATE TRIGGER airplanes_insert_type_check
BEFORE INSERT ON airplanes
FOR EACH ROW
BEGIN
IF NEW.`type` != 'airplane' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Invalid type in airplanes';
END IF;
END;;
CREATE TRIGGER airplanes_update_type_check
BEFORE UPDATE ON airplanes
FOR EACH ROW
BEGIN
IF NEW.`type` != 'airplane' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Invalid type in airplanes';
END IF;
END;;
DELIMITER ;
Thus, the type indicator in the supertype table will match only one of the subtype tables' type indicators due to the trigger restrictions, and will be enforced via foreign key constraint, preventing overlapping subtypes.
Is there anything different between the two? All I see is the additional index which I don't believe fundamentally changes anything.
I would expect the first allows each t1_1 entity to be joined to multiple t1_2 entities, and the opposite as well.
For the second, I would expect each t2_1 entity to be joined to a maximum of one t2_2 entity.
But the resulting schema's generated by MySQL Workbench appear to be basically the same.
PS. Why I am doing this? Learning about super/sub tables, and went off on a tangent.
-- MySQL Script generated by MySQL Workbench
-- 08/05/15 08:12:21
-- Model: New Model Version: 1.0
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`t1_1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t1_1` (
`id` INT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`t1_2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t1_2` (
`id` INT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`t1_1_has_t1_2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t1_1_has_t1_2` (
`t1_1_id` INT NOT NULL,
`t1_2_id` INT NOT NULL,
PRIMARY KEY (`t1_1_id`, `t1_2_id`),
INDEX `fk_t1_1_has_t1_2_t1_21_idx` (`t1_2_id` ASC),
INDEX `fk_t1_1_has_t1_2_t1_1_idx` (`t1_1_id` ASC),
CONSTRAINT `fk_t1_1_has_t1_2_t1_1`
FOREIGN KEY (`t1_1_id`)
REFERENCES `mydb`.`t1_1` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_t1_1_has_t1_2_t1_21`
FOREIGN KEY (`t1_2_id`)
REFERENCES `mydb`.`t1_2` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`t2_1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t2_1` (
`id` INT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`t2_2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t2_2` (
`id` INT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`t2_1_hs_t2_2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t2_1_hs_t2_2` (
`t2_1_id` INT NOT NULL,
`t2_2_id` INT NOT NULL,
PRIMARY KEY (`t2_1_id`, `t2_2_id`),
INDEX `fk_t2_1_hs_t2_2_t2_21_idx` (`t2_2_id` ASC),
CONSTRAINT `fk_t2_1_hs_t2_2_t2_11`
FOREIGN KEY (`t2_1_id`)
REFERENCES `mydb`.`t2_1` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_t2_1_hs_t2_2_t2_21`
FOREIGN KEY (`t2_2_id`)
REFERENCES `mydb`.`t2_2` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
IMO, talking in perspective of database design (not mysql workbench)
When using 1-n relation, we mean a not null foreign key inside cross table.
When using 1-1 relation, we mean a not null foreign key inside cross table that is the or part of a unique key of cross table.
Consider tables having these records:
T1_1(A1, B1, C1)
T2_1(A2, B2, C2)
In 1-n relation, we can have (A1, A2) multiple times in T1_has_T2 table
In 1-1 relation, we can not have (A1, A2) multiple times in T1_has_T2 table.
So Achieving 1-1 could be possible by putting foreign keys inside primary key or defining a unique key(index) on combination the foreign key columns.
I've 3 profile tables:
-student
-teacher
-staff
All profile tables have different columns(few common columns).
These tables must be connected user table, each staff, teacher, student must be having account in user table:
user table
-id
-login
-password
-etc.
What is the best ways of connecting profiles tables to user table.
I've found one solution:
Storing User Profile as properties and values in tables
*i.e. Table to store possible options, table to store user_id, option_id and value*
-No redundant data stored, all data is relevant
-Most normalised method
-Slower to retrieve and update data
updated
Below, I've created db as #user1032531 said.
Create a super table called "people". Put all attributes in this table that are common to students, teachers, and staff.
Then create a table for students, teachers, and staff where each table's primary key is a 1-to-1 to the people table, and put unique attributes in these tables.
-- MySQL Script generated by MySQL Workbench
-- 07/30/14 05:51:12
-- Model: New Model Version: 1.0
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`people`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`people` (
`idpeople` INT UNSIGNED NOT NULL,
`name` VARCHAR(45) NULL,
`birthday` DATE NULL,
`sex` CHAR(1) NULL,
PRIMARY KEY (`idpeople`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`teachers`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`teachers` (
`people_idpeople` INT UNSIGNED NOT NULL,
`unique_column` VARCHAR(45) NULL,
PRIMARY KEY (`people_idpeople`),
CONSTRAINT `fk_teachers_people`
FOREIGN KEY (`people_idpeople`)
REFERENCES `mydb`.`people` (`idpeople`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`students`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`students` (
`people_idpeople` INT UNSIGNED NOT NULL,
`unique_column` VARCHAR(45) NULL,
PRIMARY KEY (`people_idpeople`),
CONSTRAINT `fk_students_people1`
FOREIGN KEY (`people_idpeople`)
REFERENCES `mydb`.`people` (`idpeople`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`staff`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`staff` (
`people_idpeople` INT UNSIGNED NOT NULL,
`unique_column` VARCHAR(45) NULL,
PRIMARY KEY (`people_idpeople`),
CONSTRAINT `fk_staff_people1`
FOREIGN KEY (`people_idpeople`)
REFERENCES `mydb`.`people` (`idpeople`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;