2012-04-22 88 views
3

一些援助,这原本会是一个“更新”在这里另外一个问题提出的逻辑模式:Getting ERROR 1701, ERROR 1452 and ERROR 1305 errors in MySQL - Need some expertise ...需要验证数据库逻辑模式,以第三范式

我想我已经成功验证这种模式到第一和第二范式,但我不确定这是否符合第三范式。这是有问题的模式:

An attempt on a logical database model to Third Normal Form

这里是相关的代码(注:由于某种原因,我无法重新创建1:在逻辑模型说明在上面的SQL代码1间的关系):

-- database_schema.sql. 
-- This sql script creates the structure. 
-- of the rugby club database. 

DROP DATABASE IF EXISTS database_rugby; 

CREATE DATABASE database_rugby; 

USE database_rugby; 

-- Create the "person" table. 
-- 
-- This table has one:one relationships 
-- with the parent, coach and player 
-- tables. 
DROP TABLE IF EXISTS `person` ; 
CREATE TABLE `person` (
    `personID` INT(5) NOT NULL AUTO_INCREMENT , 
    `firstName` VARCHAR(50) NOT NULL , 
    `lastName` VARCHAR(50) NOT NULL , 
    `dateOfBirth` DATE NOT NULL , 
    `streetAddress` VARCHAR(150) NOT NULL , 
    `suburbAddress` VARCHAR(150) NULL DEFAULT NULL , 
    `cityAddress` VARCHAR(150) NOT NULL , 
    `photo` BLOB NULL DEFAULT NULL , 
    PRIMARY KEY (`personID`)) 
ENGINE = InnoDB; 

-- Create the "parent" table. 
DROP TABLE IF EXISTS `parent` ; 
CREATE TABLE `parent` (
    `parentID` INT(5) NOT NULL , 
    `personID` INT(5) NOT NULL , 
    PRIMARY KEY (`parentID`, `personID`), 
    FOREIGN KEY (`personID`) REFERENCES `person` (`personID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 


-- Create the "school" table. 
DROP TABLE IF EXISTS `school` ; 
CREATE TABLE `school` (
    `schoolID` INT(5) NOT NULL AUTO_INCREMENT , 
    `schoolName` VARCHAR(100) NOT NULL , 
    PRIMARY KEY (`schoolID`)) 
ENGINE = InnoDB; 


-- Create the "player" table. 
-- 
-- Inherits fields from the "person" 
-- and "school" tables. 
DROP TABLE IF EXISTS `player` ; 

CREATE TABLE `player` (
    `playerID` INT(5) NOT NULL , 
    `personID` INT(5) NOT NULL , 
    `schoolID` INT(5) NOT NULL , 
    PRIMARY KEY (`playerID`, `personID`), 
    FOREIGN KEY (`personID`) 
    REFERENCES `person` (`personID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`schoolID`) 
    REFERENCES `school` (`schoolID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 


-- Create the "coach" table. 
DROP TABLE IF EXISTS `coach`; 
CREATE TABLE `coach`(
    `coachID` INT(5) NOT NULL , 
    `dateBeganCoaching` DATE NOT NULL , 
    `personID` INT(5) NOT NULL , 
    PRIMARY KEY (`coachID`, `personID`), 
    FOREIGN KEY (`personID`) 
    REFERENCES `person` (`personID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 


-- Create the "family" table. 
-- 
-- This is a linking table 
-- that describes the many:many 
-- relationship between "parent" 
-- and "player" tables. 
DROP TABLE IF EXISTS `family` ; 
CREATE TABLE `family` (
    `parentID` INT(5) NOT NULL , 
    `playerID` INT(5) NOT NULL , 
    FOREIGN KEY (`playerID`) 
    REFERENCES `player` (`playerID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`parentID`) 
    REFERENCES `parent` (`parentID`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION) 
ENGINE = InnoDB; 


-- Create the "grade" table. 
DROP TABLE IF EXISTS `grade`; 
CREATE TABLE `grade`(
    `gradeID` INT(5) NOT NULL AUTO_INCREMENT , 
    `gradeName` VARCHAR(50) NOT NULL , 
    `minWeight` INT(3) NOT NULL , 
    `maxWeight` INT(3) NOT NULL , 
    `minAge` INT(3) NOT NULL , 
    `maxAge` INT(3) NOT NULL , 
    `ballSize` INT(1) NOT NULL , 
    PRIMARY KEY (`gradeID`)) 
ENGINE = InnoDB; 


-- Create the "coachQualification" table. 
DROP TABLE IF EXISTS `coachQualification` ; 

CREATE TABLE `coachQualification` (
    `qualID` INT(5) NOT NULL AUTO_INCREMENT , 
    `qualName` CHAR(5) NOT NULL , 
    `gradeID` INT(5) NOT NULL , 
    PRIMARY KEY (`qualID`) , 
    FOREIGN KEY (`gradeID`) 
    REFERENCES `grade` (`gradeID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 


-- Create the "homePhone" table. 
DROP TABLE IF EXISTS `homePhone` ; 
CREATE TABLE `homePhone` (
    `homePhoneID` INT(5) NOT NULL AUTO_INCREMENT , 
    `homeNumber` CHAR(9) NOT NULL , 
    PRIMARY KEY (`homePhoneID`)) 
ENGINE = InnoDB; 


-- Create the "mobilePhone" table. 
DROP TABLE IF EXISTS `mobilePhone` ; 

CREATE TABLE `mobilePhone` (
    `mobilePhoneID` INT(5) NOT NULL AUTO_INCREMENT , 
    `mobileNumber` CHAR(10) NULL DEFAULT NULL , 
    PRIMARY KEY (`mobilePhoneID`)) 
ENGINE = InnoDB; 


-- Create the "emailAddress" table. 
DROP TABLE IF EXISTS `emailAddress` ; 

CREATE TABLE `emailAddress` (
    `emailAddressID` INT(5) NOT NULL AUTO_INCREMENT , 
    `emailAddress` CHAR(10) NULL DEFAULT NULL , 
    PRIMARY KEY (`emailAddressID`)) 
ENGINE = InnoDB; 


-- Create the "Contact" table 
-- 
-- This is a linking table 
-- that describes the many:many 
-- relationships between "person" 
-- and the "homePhone", "mobilePhone", 
-- and "emailAddress" tables. 
DROP TABLE IF EXISTS `contact` ; 
CREATE TABLE `contact` (
    `personID` INT(5) NOT NULL , 
    `homePhoneID` INT(5) NOT NULL , 
    `mobilePhoneID` INT(5) NULL DEFAULT NULL , 
    `emailAddressID` INT(5) NULL DEFAULT NULL , 
    FOREIGN KEY (`personID`) 
    REFERENCES `person` (`personID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`homePhoneID`) 
    REFERENCES `homePhone` (`homePhoneID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`mobilePhoneID`) 
    REFERENCES `mobilePhone` (`mobilePhoneID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`emailAddressID`) 
    REFERENCES `emailAddress` (`emailAddressID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 


-- Create the "qualificationSet" table. 
-- 
-- This is a linking table 
-- that describes the many:many 
-- relationship between "coach" 
-- and "coachQualification" tables. 
DROP TABLE IF EXISTS `qualificationSet` ; 
CREATE TABLE `qualificationSet` (
    `coachID` INT(5) NOT NULL , 
    `qualID` INT(5) NOT NULL , 
    FOREIGN KEY (`coachID`) 
    REFERENCES `coach` (`coachID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`qualID`) 
    REFERENCES `coachQualification` (`qualID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 


-- Create the "team" table. 
DROP TABLE IF EXISTS `team` ; 
CREATE TABLE `team` (
    `teamID` INT(5) NOT NULL AUTO_INCREMENT , 
    `teamName` VARCHAR(50) NOT NULL , 
    `teamYear` INT(2) NOT NULL , 
    `gradeID` INT(5) NOT NULL , 
    PRIMARY KEY (`teamID`) , 
    FOREIGN KEY (`gradeID`) 
    REFERENCES `grade` (`gradeID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 


-- Create the "teamAllocation" table 
-- 
-- this is a linking table for a 
-- many:many relationship between 
-- team and player tables. 
DROP TABLE IF EXISTS `teamAllocation` ; 

CREATE TABLE `teamAllocation` (
    `teamID` INT(5) NOT NULL , 
    `playerID` INT(5) NOT NULL , 
    FOREIGN KEY (`teamID`) 
    REFERENCES `team` (`teamID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`playerID`) 
    REFERENCES `player` (`playerID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 


-- Create the "teamCoachAllocation" table. 
-- 
-- This is a linking table 
-- that describes the many:many 
-- relationship between "coach" 
-- and "team" tables. 
DROP TABLE IF EXISTS `teamCoachAllocation` ; 
CREATE TABLE `teamCoachAllocation` (
    `coachID` INT(5) NOT NULL , 
    `teamID` INT(5) NOT NULL , 
    FOREIGN KEY (`coachID`) 
    REFERENCES `coach` (`coachID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`teamID`) 
    REFERENCES `team` (`teamID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 

从下面这些链接:

这是我的规范化的理解到3NF:

  • 首先正常形式意味着不允许重复值
  • 第二范式装置1NF和属性是依赖于整个主键而不是主键的一部分(我认为这是分区表,如果表中的值需要以某种方式与彼此相关并进行比较)。
  • 第三范式是指2NF,没有1晶体管值(例如,如果X = Y和Y = Z,X = Z)

把知识从理论到实践是非常难受,尤其是翻译的是“练习“到正常工作的MySQL代码中。如果有人能够帮助我浏览模型并给我一些关于将模型归一化为3NF的指导,我将非常感激。

在此先感谢!

回答

1

我认为这不是在3NF,围绕着contact表。如果我错了,这仍然是一种存储数据的不好方法,应该可能改变。

很抱歉,如果这是一个有点糊涂了......

这是完全有可能具有以下结构在contact表作为整个表的主键:

 
+----------+-------------+---------------+---------+ 
| personid | homephoneid | mobilephoneid | emailid | 
+----------+-------------+---------------+---------+ 
|  1 |   1 |    1 |  1 | 
|  1 |   1 |    1 |  2 | 
|  1 |   1 |    2 |  3 | 
+----------+-------------+---------------+---------+ 

,你可以见homephoneidmobilephoneid都是重复的,所以更新表homephone将导致3更新为contact

我与数据模型不同意,你需要一个personhomehone我没有一个,只有一个移动。在这种情况下,创建新的person时,还必须创建新的contact和新的homephone

由于contact仅仅是一个主键,主键的值不能为空,也需要创建一个mobilephoneemailaddress的,这意味着person取决于emailaddress

由于emailaddress依赖于contact,依次取决于person您创建了一个循环依赖关系,它打破3NF。

当我看到它,你有两个选择,如果你想确保人们有一个家庭电话号码:

  1. 如果你只想要一个person一个homephone再加入这 到person表。这是唯一的联系级别信息,并且 应该存储在那里。
  2. 如果你想使人们有多个家庭电话号码 - 记住,多人可以使用同一个电话号码 - 但 不关心手机,那么你需要创建一个表 personhomephones,比方说,与主键personid, homephoneid,而不是将homephoneid放在联系人表中。

就我个人而言,我不会这样做。我不能确保有人必须有一个家庭电话号码,而是一个主要的电话号码,你不关心它是什么类型。我可以让人们将联系人添加不同的方法,但允许这些不存在

这需要以下结构:

  • person - 添加primaryPhoneID
  • primaryphone (primaryphoneID, phonenumber) - PK primaryphoneID

然后对于允许不存在的联系方式:

  • contactType (contactTypeID, contactType) - PK contactTypeID
  • contact (contactID, contactTypeID, value) - PK contactID, contactTypeID
  • personContact (personID, contactID, contactTypeID) - PK一切

虽然这可能会导致重复contactprimaryphone他们的数据不同的位,我认为这是好的之间。如果您对不允许在所有任何重复是坚持你必须从接触的其他方法,使模型更加复杂,分离出的手机:

  • phonetype (phoneTypeId, phoneType)
  • phone (phoneID, phoneTypeID, phonenumber) - PK phoneID, phoneTypeID
  • contactPhone (personID, phoneTypeID, phoneID) - PK一切
+0

干杯的建议奔:)我并没有实现你说的到底是什么,但我觉得我有一些作品(我可以把一个更新的模型如果需要的话)。我的讲师说了类似于你的东西,我尝试用我的建议自己实施一些东西。我测试过插入和删除,到目前为止一切正常,一旦数据库完成,我会通过一些更严格的测试。 – Rob 2012-04-23 09:49:56

1

有一个algorithm最终分解您的架构中的每个关系,以获得3NF中的等效架构。 Google很好!

要获得关于您的模式设计的提示,您至少应该描述关于您需要表示的实体的上下文和功能约束。