确保 SQL 超类型 table 具有子类型
Ensure SQL supertype table has subtype
我有以下数据库架构。
由于 non-NULL FK 约束,确保每个父记录的实体记录都存在是微不足道的。
如何确保每个父记录都存在一个子记录?
-- MySQL Script generated by MySQL Workbench
-- 01/07/15 06:01:50
-- 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`.`entity`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`entity` (
`identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`identity`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`parent1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`parent1` (
`entity_identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`entity_identity`),
CONSTRAINT `fk_parent1_entity`
FOREIGN KEY (`entity_identity`)
REFERENCES `mydb`.`entity` (`identity`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`parent2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`parent2` (
`entity_identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`entity_identity`),
CONSTRAINT `fk_parent2_entity1`
FOREIGN KEY (`entity_identity`)
REFERENCES `mydb`.`entity` (`identity`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`child1_1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`child1_1` (
`parent1_entity_identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`parent1_entity_identity`),
CONSTRAINT `fk_child1_1_parent11`
FOREIGN KEY (`parent1_entity_identity`)
REFERENCES `mydb`.`parent1` (`entity_identity`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`child1_2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`child1_2` (
`parent1_entity_identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`parent1_entity_identity`),
CONSTRAINT `fk_child1_2_parent11`
FOREIGN KEY (`parent1_entity_identity`)
REFERENCES `mydb`.`parent1` (`entity_identity`)
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;
在您的设计中使用超级类型将确保添加更多 child 表成为可能,而无需重构每个现有表和应用程序。这意味着 parent 将不知道 children.
如果您面临 parent 没有 child 的记录,这可能是应用程序存在缺陷的证据。
顺便说一句,强制执行此检查约束的机制将使用触发器。
作为提示(如果使用 ORM)将 parent 个抽象的实体 类 将是一个替代方案。
我认为这必须由应用程序强制执行。
尝试使用触发器强制执行此操作会产生顺序问题。如果你不能在没有实体的情况下创建一个父实体,并且你不能在没有父实体的情况下创建一个实体,那么你先创建哪个?在您创建任一记录时,数据库引擎无法 "know" 您是否要在接下来的几毫秒内创建另一条记录。
不过,在代码中,您可以收集所有数据,然后在所有必需的数据都可用时写入两条记录,否则就发出错误消息。
根据您的要求,您可以有一个在创建实体记录时触发的触发器,它会自动创建具有默认值的父记录,反之亦然。这样的虚拟记录是否有用,我不能在不了解您的应用程序的情况下说。
您可以有一个创建实体和父记录的存储过程,因此如果程序调用存储过程,它必须创建两者。但我不知道,在我熟悉的任何数据库引擎中,程序可以创建记录的唯一方法是通过特定的存储过程。因此,强制使用该过程将依赖于遵循约定的程序员。如果程序员按照约定使用存储过程,那么他们应该能够按照约定始终通过他们使用的任何方法创建这两个记录。
我的想法是创建一个库函数来创建对,并且 returns 如果您没有创建两者所需的所有数据,则会出现某种错误情况。彻底调试此功能。然后告诉程序员总是使用这个函数来创建记录。这样一来,如果有问题,就只有一个地方可以查看。
我有以下数据库架构。
由于 non-NULL FK 约束,确保每个父记录的实体记录都存在是微不足道的。
如何确保每个父记录都存在一个子记录?
-- MySQL Script generated by MySQL Workbench
-- 01/07/15 06:01:50
-- 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`.`entity`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`entity` (
`identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`identity`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`parent1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`parent1` (
`entity_identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`entity_identity`),
CONSTRAINT `fk_parent1_entity`
FOREIGN KEY (`entity_identity`)
REFERENCES `mydb`.`entity` (`identity`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`parent2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`parent2` (
`entity_identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`entity_identity`),
CONSTRAINT `fk_parent2_entity1`
FOREIGN KEY (`entity_identity`)
REFERENCES `mydb`.`entity` (`identity`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`child1_1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`child1_1` (
`parent1_entity_identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`parent1_entity_identity`),
CONSTRAINT `fk_child1_1_parent11`
FOREIGN KEY (`parent1_entity_identity`)
REFERENCES `mydb`.`parent1` (`entity_identity`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`child1_2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`child1_2` (
`parent1_entity_identity` INT NOT NULL,
`stuff` VARCHAR(45) NULL,
PRIMARY KEY (`parent1_entity_identity`),
CONSTRAINT `fk_child1_2_parent11`
FOREIGN KEY (`parent1_entity_identity`)
REFERENCES `mydb`.`parent1` (`entity_identity`)
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;
在您的设计中使用超级类型将确保添加更多 child 表成为可能,而无需重构每个现有表和应用程序。这意味着 parent 将不知道 children.
如果您面临 parent 没有 child 的记录,这可能是应用程序存在缺陷的证据。
顺便说一句,强制执行此检查约束的机制将使用触发器。
作为提示(如果使用 ORM)将 parent 个抽象的实体 类 将是一个替代方案。
我认为这必须由应用程序强制执行。
尝试使用触发器强制执行此操作会产生顺序问题。如果你不能在没有实体的情况下创建一个父实体,并且你不能在没有父实体的情况下创建一个实体,那么你先创建哪个?在您创建任一记录时,数据库引擎无法 "know" 您是否要在接下来的几毫秒内创建另一条记录。
不过,在代码中,您可以收集所有数据,然后在所有必需的数据都可用时写入两条记录,否则就发出错误消息。
根据您的要求,您可以有一个在创建实体记录时触发的触发器,它会自动创建具有默认值的父记录,反之亦然。这样的虚拟记录是否有用,我不能在不了解您的应用程序的情况下说。
您可以有一个创建实体和父记录的存储过程,因此如果程序调用存储过程,它必须创建两者。但我不知道,在我熟悉的任何数据库引擎中,程序可以创建记录的唯一方法是通过特定的存储过程。因此,强制使用该过程将依赖于遵循约定的程序员。如果程序员按照约定使用存储过程,那么他们应该能够按照约定始终通过他们使用的任何方法创建这两个记录。
我的想法是创建一个库函数来创建对,并且 returns 如果您没有创建两者所需的所有数据,则会出现某种错误情况。彻底调试此功能。然后告诉程序员总是使用这个函数来创建记录。这样一来,如果有问题,就只有一个地方可以查看。