Mysql 当任何一个表都是正确选项时,将一个表链接到另外两个表的正确方法是什么 前言

Mysql 当任何一个表都是正确选项时,将一个表链接到另外两个表的正确方法是什么 前言,mysql,database,database-design,normalization,Mysql,Database,Database Design,Normalization,我有三张表:客户、个人和公司,客户可以是个人,也可以是公司,但不能两者兼而有之。我想找出正确连接这三张表的一般意见 举例说明 这三个表是“客户”、“公司”和“个人”,生成基本表的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=@@SQ

我有三张表:客户、个人和公司,客户可以是个人,也可以是公司,但不能两者兼而有之。我想找出正确连接这三张表的一般意见

举例说明 这三个表是“客户”、“公司”和“个人”,生成基本表的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;
这是基本表,它们之间没有链接。我曾尝试过几种连接表格的方法,但没有一种是正确的。第一种方法是基本上在Customer表中发布一个“IndividualID”和“CompanyID”,并用一个布尔值来表示它是哪一个,但这使得它有可能被填充,并且无法直接用DB来加强它。它也只是感觉不对,就像这样:

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;
另一种方法是在客户和链接他们的其他两个表之间添加两个表,这两个表感觉更好,但并不完美,因为这两个表中都有链接。看起来是这样的:

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;
正如我提到的,最后一个选项是我喜欢的方法,但它仍然感觉不正确,并且仍然可能导致问题。因此:

问题:
  • 还有其他选择吗
  • 对所述选项的总体意见是什么?我是否错过了这些选项的任何优点/缺点

提前谢谢。

就我个人而言,我会根据面向对象的原则做一些事情

顾客:会是超类。它将包含所有公司和个人共有的元素。即Id、名称(可能还有主地址或主地址表的Id,以及任何客户共有的任何其他内容)加上“类型”字段(例如:“IND”、“COM”)

个人:这有一个客户的外键和个人特定的所有字段,如中间名、DOB等。外键也是唯一的

公司:相同-客户和公司特定字段的外键。外键也是唯一的

理论上,个人和公司记录都指向同一客户条目是可能的,但类型字段将有助于确保您始终可以在客户仅被视为个人或公司的情况下编写查询,而决不能同时将两者都视为客户

例如:

    Select * from Individuals where exists 
    (select 'x" from Customers 
                where customer-id=individual-id and type="IND").
------------------更新:

您始终可以为这两种类型的客户创建视图,以缓解拆分带来的问题:

Select Individuals.id, 
       Individuals.field1, 
       Individuals.field2, 
       Customer.FieldX, Customer.FieldY 
 from Individuals ind, Customers Cus 
 where ind.id=cus.id and cus.type="IND" 
是一种从两个表中提取字段“重建”单个客户的方法。这允许您作为一个整体访问它,至少在阅读时是这样


实际上,我不确定拆分两个不同表上的字段时会出现什么问题。

将所有公共字段放入
客户表中。
Company
Person
表只有特定于每个表的列。
Customer.CustomerType
是鉴别器


看看一些

你真的需要中间的表格“个人客户”和“公司客户”吗?这些真的是m:n关系吗?这意味着一个客户可以与多个公司或个人关联(反之亦然,一个公司可以与多个客户关联)?还是仅仅是1:1

如果是1:1,您可以在表之间插入一个列CustomerID,并将其添加到“个人”和“公司”表中。这将解决“无法将公共数据移动到客户表”的问题。并将CustomerID添加到主键或新的唯一键,以防止这些表中出现重复条目


客户最终成为公司和个人的可能性仍然存在,但这是一个问题,除非你按照p.marino和Damir的建议修改表格,否则你不可能(轻松地)解决这个问题。只要数据存储在多个表中,就不能在数据库中使用简单的主键或唯一键在mySQL中强制执行该要求。只有应用程序逻辑或存储函数/过程才能做到这一点。

因此基本上与我的两个示例中的第一个相同,但两个ID链接指向customers表中的同一列?@Zasurus;是的,
CustomerID
传播到子类型表;它同时是主键和外键。鉴别器
{C,P}
确定记录的类型。@Zasursu-这基本上是我在回答中描述的,但你说它在你的场景中不起作用。@DamirSudarevic:正如P.marino所说,这与他的回答相同(但不太详细:P),所以同样的问题也适用。我无法将所有常用记录都移动到客户记录中,因为它们需要分开,否则会:(没问题-Damir的答案有一个很好的图表,所以可能比我的更容易理解。我只是想指出,我们说的是同一件事。很抱歉,我没有提到我在应用程序中使用了其他地方的公司和个人,所以像这样合并他们并不是一个真正的选择。不过,谢谢。这是我提出的第一个解决方案我觉得我必须选择我原来的一个选择。我想答案是没有更好的办法了!:(我会将此标记为已接受的答案,因为其中没有一个“解决”了问题,但这解释了我使用的解决方案(即使是在我的问题:p中),它会给你一些代表!)