为超类型表强制执行单个子类型SQL表

时间:2016-05-25 16:04:09

标签: mysql sql database-design

我有一个名为“vehicles”的超类表。我还有三个子类型表,称为“飞机”,“汽车”和“自行车”,这些子类型表中只有一个必须链接到车辆超类型表(换句话说,必须使用车辆主键ID作为主键ID)。

如何对其进行建模以强制执行此行为?

编辑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;

3 个答案:

答案 0 :(得分:0)

我认为插入车辆和任何其他子类型应该同时进行。因此,您可以获取车辆ID并将其作为新的子类型PK ID。如果您同时拥有所有信息,则可以创建转码并首先插入车辆记录,然后插入子类型记录。然后提交你的transscation,否则回滚它。如果您想知道哪条记录属于哪种子类型表记录,您可以在车辆表中添加一列,例如可以有3个不同的值,例如0,1,2,表示哪条记录属于哪个子表。 java中的枚举可用于类似的内容以获得更多说明

答案 1 :(得分:0)

查看您提出的架构,我认为没有理由让您为每种车型分别设置表格,或者甚至是包含允许车辆类型的单独表格。您的车辆特定表基本上都是相同的,这意味着您可以轻松地折叠到单个表中,并且您可以使用ENUM字段来强制允许的车辆类型。

为什么不只是拥有如下车辆表?

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;

这种方法完全消除了5个表中的4个,这意味着在对这些记录执行CRUD操作时,您不再需要考虑使用连接,外键约束等。

答案 2 :(得分:0)

要强制执行独占子类型,请将type指示符复制到每个子类型表中并使用复合外键约束:

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;

接下来,您需要限制每个表中type的值。不幸的是,MySQL不支持检查约束,因此您需要使用触发器:

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 ;

因此,超类型表中的type指标只匹配一个子类型表'由于触发器限制导致的type指标,并将通过外键约束强制执行,防止重叠的子类型。