【问题标题】:SQL Many-to-Many Relationship Between Multiple Tables多个表之间的 SQL 多对多关系
【发布时间】:2015-05-27 02:43:40
【问题描述】:

我有一个我正在尝试在 SQL 上创建的数据库,并且我正在尝试将这些关系连接在一起。共有三个表:superhero、power 和 superheroPower。表 superhero 和 power 是多对多的关系,由表 superheroPower 表示。

以下语法对于表(以及其他所有内容)之间的外键是否正确?另外,就这些表的设置而言,还有其他建议吗?

CREATE TABLE superhero( id INT NOT NULL AUTO_INCREMENT, 
heroName VARCHAR(255) NOT NULL, 
firstName VARCHAR(255), 
lastName VARCHAR(255), 
firstAppearance DATE, 
gender VARCHAR(255), 
bio TEXT, 
universe VARCHAR(255), 
PRIMARY KEY(id)
) ENGINE=InnoDB;

CREATE TABLE power( 
id INT NOT NULL AUTO_INCREMENT, 
name VARCHAR(255) NOT NULL, 
description TEXT NOT NULL,
PRIMARY KEY(id)
) ENGINE=InnoDB;

CREATE TABLE superheroPower( 
superheroID INT, 
powerID INT, 
PRIMARY KEY(superheroID, powerID), 
FOREIGN KEY(superheroID) REFERENCES superhero(id), 
FOREIGN KEY(powerID) REFERENCES power(id) 
) ENGINE=InnoDB;

【问题讨论】:

  • 最简单的找出方法是尝试一下,看看会发生什么:-)
  • 可能更适合代码审查

标签: mysql sql


【解决方案1】:

是的,那里的一切看起来都还不错。但是……


几点说明:

我们会为 gender 列使用较短的数据类型;我不认为我们需要 255 个字符来表达这一点。 (强制执行的行的最大大小有限制。)如果只有几个值,我们会考虑 ENUM 数据类型。

我们还可能在其中几个列上添加NOT NULL 约束,例如 heroname、firstname、lastname。我们也可能会添加DEFAULT ''。有时,出于某种原因,我们确实需要允许 NULL 值,但我们尽可能使用NOT NULL

我对@9​​87654326@ 列犹豫不决。使用 TEXT 数据类型没有任何问题,但我只是怀疑这些可能“隐藏”了一些可能更好地存储在其他列中的信息。

对于外键,我们会按照我们使用的模式为约束分配一个名称,并且还可能添加ON UPDATE CASCADE ON DELETE CASCADE

CONSTRAINT FK_superheroPower_power FOREIGN KEY (powerID) 
  REFERENCES power(id) ON UPDATE CASCADE ON DELETE CASCADE

关于标识符(表名和列名)的说明

我们这样做的方式,所有表名都是小写。 (我们有一个 MySQL 选项集,它强制所有表名小写。)我们这样做是为了避免不同操作系统/文件系统的不兼容问题(其中一些区分大小写,而另一些不区分)。

另外,表名是单数的。表的名称命名表的一行 所代表的内容。我们也不将_table 作为名称的一部分。

MySQL 中的列名从不区分大小写,但我们也总是使用小写的列名。我们不“驼峰式”我们的列名,我们使用下划线字符作为分隔符,例如power_idpowerIDhero_nameheroName


跟进

我上面的“注释”不是必须遵守的具体规则;这些只是我们使用的模式。

遵循这些模式并不能保证我们将拥有一个成功的软件,但它确实对我们有所帮助。

为了您的参考,我将展示这些桌子看起来像是我们商店的“第一批”,作为另一种模式的说明;这不是“正确的方式”,它只是我们作为一个团队确定的“一种方式”。

CREATE TABLE superhero
( id               INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'pk'
, hero_name        VARCHAR(255) NOT NULL                COMMENT ''
, first_name       VARCHAR(255) NOT NULL DEFAULT ''     COMMENT ''
, last_name        VARCHAR(255) NOT NULL DEFAULT ''     COMMENT ''
, first_appearance DATE                                 COMMENT 'date superhero first appeared'
, gender           ENUM('female','male','other')        COMMENT 'female,male or other'
, biography_text   TEXT                                 COMMENT ''
, universe         VARCHAR(255)                         COMMENT ''
, PRIMARY KEY(id)
, UNIQUE KEY superhero_UX1 (hero_name) 
) ENGINE=InnoDB;

CREATE TABLE power
( id               INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'pk'
, name             VARCHAR(255) NOT NULL                COMMENT ''  
, description_text TEXT NOT NULL                        COMMENT '' 
, PRIMARY KEY(id)
, UNIQUE KEY power_UX1 (name)
) ENGINE=InnoDB;

CREATE TABLE superheropower
( superhero_id   INT UNSIGNED NOT NULL         COMMENT 'pk, fk ref superhero'
, power_id       INT UNSIGNED NOT NULL         COMMENT 'pk, fk ref power'
, PRIMARY KEY(superhero_id, power_id)
, CONSTRAINT FK_superheropower_superhero 
     FOREIGN KEY(superhero_id) REFERENCES superhero(id)
     ON UPDATE CASCADE ON DELETE CASCADE
, CONSTRAINT FK_superheropower_power
     FOREIGN KEY (power_id) REFERENCES power(id) 
     ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB;

【讨论】:

  • 只是为了清楚。我包含的笔记只是关于我工作的一家特定商店的详细信息。这并不是说每个人都应该这样做。这只是关于我们的特定商店的一些说明;我大多只是指出我在我们店里看到的会有所不同的东西。我们非常一致,遵循相当严格的模式和指导方针。大多数模式都有充分的理由,当有充分的理由时,也有偏离它们的空间。其他商店遵循对他们更好工作的不同模式,以及他们需要做什么。
【解决方案2】:

您的设计似乎在正确的轨道上,这是我会使用的表格 - 为您可能会搜索的字段添加一些索引并添加 CONSTRAINT 键所需的操作

CREATE TABLE `_superhero` (
  `id` int(11) NOT NULL auto_increment,
  `heroName` varchar(255) NOT NULL,
  `firstName` varchar(255) default NULL,
  `lastName` varchar(255) default NULL,
  `firstAppearance` date default NULL,
  `gender` enum('Other','Female','Male') default NULL,
  `bio` text,
  `universe` varchar(255) default NULL,
  PRIMARY KEY  (`id`),
  KEY `indxHname` (`heroName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `_power` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `description` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `indx4` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `_superheropower` (
  `superheroID` int(11) NOT NULL default '0',
  `powerID` int(11) NOT NULL default '0',
  PRIMARY KEY  (`superheroID`,`powerID`),
  KEY `indx1` (`superheroID`),
  KEY `indx2` (`powerID`),
  CONSTRAINT `fk2` FOREIGN KEY (`powerID`) REFERENCES `_power` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `fk1` FOREIGN KEY (`superheroID`) REFERENCES `_superhero` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

【讨论】:

    【解决方案3】:

    编辑[1]:这是一个关于我将如何做的 SQL 代码版本!

    CREATE TABLE superhero
    ( 
    Superheo_id INT NOT NULL AUTO_INCREMENT, 
    heroName VARCHAR(255) NOT NULL, 
    firstName VARCHAR(255)NULL,
    lastName VARCHAR(255)NULL, 
    firstAppearance DATE NULL, 
    gender VARCHAR(255) NULL, 
    bio TEXT NULL, 
    universe VARCHAR(255) NULL, 
    CONSTRAINT SUPERHERO_PK PRIMARY KEY(SUPERHERO_id)
    );
    
    CREATE TABLE power
    ( 
    POWER_id INT NOT NULL AUTO_INCREMENT, 
    name VARCHAR(255) NOT NULL, 
    description TEXT NOT NULL,
    CONSTRAINT POWER_PK PRIMARY KEY(POWER_id)
    );
    
    CREATE TABLE superheroPower
    ( 
    superheroID INT DEFAULT(0) NOT NULL, 
    powerID INT DEFAULT(0) NOT NULL, 
    CONSTRAINT SUPERHEROPOWERS_SUPERHERO_FK FOREIGN KEY(superheroID) REFERENCES superhero(id), 
    CONSTRAINT SUPERHEROPOWERS_POWERS_FK FOREIGN KEY(powerID) REFERENCES power(id) 
    );
    

    edit[2]:您可以将 null 更改为 not null,反之亦然,具体取决于您是否希望用户在不安装其他信息的情况下移动过去.我以前从未在我的 sql 表中使用过 Auto_increment,所以对我来说这是我刚刚从你那里学到的新东西

    【讨论】:

    • 有些你所说的更正只是偏好,有些则删除了重要信息。此外,使用 AUTO_INCREMENT 是一种常见的做法。
    • @Gorilla:可以遵循几种不同的模式。例如,有些人会反对使用代理id 列的模式。我们碰巧对实体表使用了代理整数主键,并且我们使用id 作为列名。 (我们的模式是有原因的。)我们遵循的模式对我们有用;我们的模式并不是成功软件的唯一模式,它对我们来说是“正确的”。作为另一个示例,我们将所有表名和列名都小写。没有规则说这是“正确”的做法。这只是我的团队遵循的指导方针。
    • @spencer7593 我完全理解,每个人都有自己的方式。就像我上面的代码一样,我让我更容易理解以及如何编写我的 SQL 语法。我还在学校学习计算机编程,所以我没有其他公司喜欢那里的代码偏好的工作经验。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多