问题
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;
回答1:
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 valuereligion
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.
来源:https://stackoverflow.com/questions/42165377/group-dependency-sql-design