Введение
У меня есть три таблицы «Клиенты, физические лица и компании», и клиент может быть физическим лицом или компанией, но не обоими. Я хочу узнать общее мнение о том, как правильно связать эти три таблицы.
Подробности с примером
Три таблицы - это «клиенты», «компании» и «частные лица», а код MySQL для генерации базовых таблиц:
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';
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`customers`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`customers` (
`CustomerID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
PRIMARY KEY (`CustomerID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`individuals`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`individuals` (
`IndividualID` INT NOT NULL AUTO_INCREMENT ,
`First Name` VARCHAR(45) NULL ,
`Last Name` VARCHAR(45) NULL ,
`DOB` DATE NULL ,
PRIMARY KEY (`IndividualID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`companies`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`companies` (
`CompanyID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(60) NULL ,
`StartedDate` DATE NULL ,
`Address` VARCHAR(500) NULL ,
PRIMARY KEY (`CompanyID`) )
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Это базовые таблицы без ссылок между ними. Я играл с несколькими методами связывания таблиц, но ни один из них не чувствовал себя правильным. Первый метод состоял в том, чтобы в основном опубликовать «IndividualID» и «CompanyID» в таблице клиентов и логическое значение, чтобы сказать, какой это был, но это оставляло его открытым, чтобы потенциально заполнить и не было возможности подкрепить его БД напрямую Кроме того, он просто не чувствовал себя правильно, что было так:
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';
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`companies`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`companies` (
`CompanyID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(60) NULL ,
`StartedDate` DATE NULL ,
`Address` VARCHAR(500) NULL ,
PRIMARY KEY (`CompanyID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`individuals`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`individuals` (
`IndividualID` INT NOT NULL AUTO_INCREMENT ,
`First Name` VARCHAR(45) NULL ,
`Last Name` VARCHAR(45) NULL ,
`DOB` DATE NULL ,
PRIMARY KEY (`IndividualID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`customers`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`customers` (
`CustomerID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
`bIsCompany` TINYINT(1) NOT NULL ,
`IndividualID` INT NULL ,
`CompanyID` INT NULL ,
PRIMARY KEY (`CustomerID`) ,
INDEX `Customer_Company` (`CompanyID` ASC) ,
INDEX `Customer_Individual` (`IndividualID` ASC) ,
CONSTRAINT `Customer_Company`
FOREIGN KEY (`CompanyID` )
REFERENCES `mydb`.`companies` (`CompanyID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `Customer_Individual`
FOREIGN KEY (`IndividualID` )
REFERENCES `mydb`.`individuals` (`IndividualID` )
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;
Другой метод состоял в том, чтобы добавить две таблицы между клиентом и двумя другими таблицами, которые связывали их, и это было лучше, но не идеально, так как опять вы МОЖЕТЕ иметь связь в обеих. Это выглядело так:
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';
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`customers`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`customers` (
`CustomerID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
PRIMARY KEY (`CustomerID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`individuals`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`individuals` (
`IndividualID` INT NOT NULL AUTO_INCREMENT ,
`First Name` VARCHAR(45) NULL ,
`Last Name` VARCHAR(45) NULL ,
`DOB` DATE NULL ,
PRIMARY KEY (`IndividualID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`companies`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`companies` (
`CompanyID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(60) NULL ,
`StartedDate` DATE NULL ,
`Address` VARCHAR(500) NULL ,
PRIMARY KEY (`CompanyID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`company_customer`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`company_customer` (
`CustomerID` INT NOT NULL ,
`CompanyID` INT NOT NULL ,
PRIMARY KEY (`CustomerID`, `CompanyID`) ,
INDEX `CompanyCustomer_CompanyID` (`CompanyID` ASC) ,
INDEX `CompanyCustomer_CustomerID` (`CustomerID` ASC) ,
CONSTRAINT `CompanyCustomer_CompanyID`
FOREIGN KEY (`CompanyID` )
REFERENCES `mydb`.`companies` (`CompanyID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `CompanyCustomer_CustomerID`
FOREIGN KEY (`CustomerID` )
REFERENCES `mydb`.`customers` (`CustomerID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`individual_customer`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`individual_customer` (
`IndividualID` INT NOT NULL ,
`CompanyID` INT NOT NULL ,
PRIMARY KEY (`IndividualID`, `CompanyID`) ,
INDEX `CompanyCustomer_CompanyID` (`IndividualID` ASC) ,
INDEX `CompanyCustomer_CustomerID` (`IndividualID` ASC) ,
CONSTRAINT `IndividualCustomer_CompanyID0`
FOREIGN KEY (`IndividualID` )
REFERENCES `mydb`.`individuals` (`IndividualID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `IndividualCustomer_CustomerID0`
FOREIGN KEY (`IndividualID` )
REFERENCES `mydb`.`customers` (`CustomerID` )
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;
Как я уже говорил, последний вариант был тем методом, который я предпочел, но он все еще не был корректным и мог привести к проблемам. SO:
Вопросы:
- Есть ли другие варианты
- Каково общее мнение по поводу указанных вариантов, и я упустил какие-либо преимущества / недостатки этих вариантов.
Заранее спасибо.