rat*_*ing 4 mysql inheritance polymorphic-associations
I have a MySQL database with 3 tables holding the main classes of data:
companies (company_id)
persons (person_id, company_id)
loans (loan_id, company_id)
Run Code Online (Sandbox Code Playgroud)
Both a 'loan' and a 'person' belong to a company. A company can have loans and a company can have people (such as directors, employees etc.)
There are several scenarios where other data can belong to either a company, a person or a loan, such as 'notes'. For example a user can add a 'note' specific to either a company, a person or a loan.
There are other examples of this such as 'addresses' and 'phone numbers', which can belong to either a company or a person.
I obviously want to have a single table for data such as 'notes', 'addresses' and 'phone numbers', however I am struggling with the best way to link these to companies, people and loans.
Lets use 'notes' as our example here.
Is it better practice to:
1/ Have 3 extra tables linking 'notes' to companies people and loans:
notes(note_id)
persons_notes(person_id, note_id)
companies_notes(company_id, note_id)
loans_notes (loan_id, note_id)
2/ Have a single table 'entities' which has a primary key entity_id used to link all 3 tables:
entities(entity_id)
persons(person_id, entity_id)
companies(company_id, entity_id)
loans (loan_id, entity_id)
notes (note_id, entity_id)
Run Code Online (Sandbox Code Playgroud)
后者在逻辑上有一定道理,但感觉不对,因为个人和公司是与贷款完全不同的一类数据。不知怎的,感觉很脏。
票据和地址将与贷款、个人和公司形成一对多的关系。也就是说,一个公司可能有许多地址或注释。这就是我考虑链接表的原因。
公司可以拥有注册地址和无限的交易地址。一个人可以有当前地址和以前的地址(如果当前地址少于 3 年)。
在这种情况下,拥有贷款(商业贷款)的是公司。人属于公司,通常是公司的董事。因此,一家公司可以有很多人和很多贷款。
这个问题(以各种形式)经常出现在这个论坛上。
它被称为 EAV(实体属性值)。有充分的理由,它被称为反模式。不使用这种形式的数据模型的原因有很多。它们在此处、此处和此处进行了概述(以及内的链接 + 查看同一主题中其他海报的回复)。
并非所有人都同意 EAV 总是一件坏事,只是在大多数情况下。Aaron Bertrand(这个小组的一个大人物)写了这篇关于这个问题的帖子。然而,我的建议是坚持传统的设计,并且(可能)让自己的生活更轻松。
为什么不像你描述的那样只有三个主表
和两个“附属”表
然后 Person、Company 和 Loan 可以有 Address_id 和 Note_id 字段。不需要复杂的链接表(至少现在还没有:-))。或者首先,您甚至可以在主表中包含注释和地址(如果有一个地址和一个注释 (BLOB) 字段)?
无论您做什么,在您成为经验丰富的数据建模师之前,请避免使用 EAV。ps 欢迎来到论坛!
[编辑]
您能告诉我们您使用的是哪个 RDBMS 吗?可能对我的回复有些影响。这里的版主不喜欢长时间的乒乓式聊天。
我“拼凑”了一个图表和脚本,应该能让你开始。
任何进一步的问题/问题,让我知道。大部分应用程序设计和数据建模都是反复试验——您生成一个数据模型,开始针对它进行编程,然后您会发现您的原始想法无法实现的各种方式。这就是原型设计的目的。给它一个bash,然后解决问题。
还有那个图表中的脚本。
CREATE TABLE IF NOT EXISTS `mydb`.`Person` (
`Person_id` INT NOT NULL AUTO_INCREMENT,
`Name` VARCHAR(45) NOT NULL,
`Employed_by` INT NULL,
PRIMARY KEY (`Person_id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `mydb`.`Loan` (
`Loan_id` INT NOT NULL AUTO_INCREMENT,
`Amount` DECIMAL NOT NULL,
`Other_fields` VARCHAR(45) NULL,
PRIMARY KEY (`Loan_id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `mydb`.`Person_loan` (
`Person_id` INT NOT NULL,
`Loan_id` INT NOT NULL,
INDEX (`Person_id` ASC),
INDEX (`Loan_id` ASC),
INDEX (`Person_id` ASC, `Loan_id` ASC),
CONSTRAINT `Person_Loan_P_FK`
FOREIGN KEY (`Person_id`)
REFERENCES `mydb`.`Person` (`Person_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `Person_Loan_L_FK`
FOREIGN KEY (`Loan_id`)
REFERENCES `mydb`.`Loan` (`Loan_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `mydb`.`Company` (
`Company_id` INT NOT NULL AUTO_INCREMENT,
`Company_name` VARCHAR(45) NULL,
PRIMARY KEY (`Company_id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `mydb`.`Works_for` (
`Person_id` INT NULL,
`Company_id` INT NULL,
INDEX `Works_For_P_FK_idx` (`Person_id` ASC),
INDEX `Works_For_C_FK_idx` (`Company_id` ASC),
CONSTRAINT `Works_For_P_FK`
FOREIGN KEY (`Person_id`)
REFERENCES `mydb`.`Person` (`Person_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `Works_For_C_FK`
FOREIGN KEY (`Company_id`)
REFERENCES `mydb`.`Company` (`Company_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `mydb`.`Company_loan` (
`Company_id` INT NOT NULL,
`Loan_id` INT NOT NULL,
INDEX `Company_loan_C_L_PK` (`Company_id` ASC, `Loan_id` ASC),
INDEX `Company_Loan_L_FK_idx` (`Loan_id` ASC),
CONSTRAINT `Company_Loan_C_FK`
FOREIGN KEY (`Company_id`)
REFERENCES `mydb`.`Company` (`Company_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `Company_Loan_L_FK`
FOREIGN KEY (`Loan_id`)
REFERENCES `mydb`.`Loan` (`Loan_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Run Code Online (Sandbox Code Playgroud)