使用生成的主键引用表

Posted

技术标签:

【中文标题】使用生成的主键引用表【英文标题】:Referencing table with generated primary keys 【发布时间】:2015-04-29 16:36:16 【问题描述】:

我正在尝试增加我的 MySQL 数据库架构的约束,为每个表添加外键约束。

表 1:用户

    +---------+----------+-------------
    | id      | username | Other fields
    +---------+----------+-------------
    | 1       | John     |
    | 2       | Mark     |
    +---------+----------+-------------

idINT(11) UNSIGNED NOT NULL AUTO_INCREMENT

用户名` VARCHAR(50) NOT NULL

主键 (id)

表 2:DISKS(这与 USERS 具有一对多关系)

    +---------+----------+-----------+-------------
    | id      | id_user  | disk_name | Other fields
    +---------+----------+-----------+-------------
    | 1       | 1        | disk A    |
    | 2       | 2        | disk B    |
    +---------+----------+-----------+-------------

id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT

id_user INT(11) 非空,

主键 (id,id_user) 索引fk_disks_idx (id ASC)

约束fk_disks

外键 (id)

参考database.USERS (id)

不删除任何操作

更新无操作)

表 3:FILES(这与 DISKS 具有一对多关系)

    +---------+----------+----------+-----------+-------------
    | id      | id_disk  | id_user  | file_name | Other fields
    +---------+----------+----------+-----------+-------------
    | 1       | 1        | 1        |           |
    | 2       | 2        | 2        |           |
    +---------+----------+----------+-----------+-------------

id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT

id_user INT(11) 非空

id_disk INT(11) 非空

主键 (id,id_disk,id_user) 索引fk_files_idx (id ASC, id_user ASC)

约束fk_files

外键(id_diskid_userid_user

参考database.DISKS (id)

不删除任何操作

更新无操作)

表 2:FILES_ON_NAS(这与 FILES 具有一对一关系)

    +-------+----------+----------+----------+-----------+-------------
    | id    | id_files | id_user  | id_disk  | file_name | Other fields
    +-------+----------+----------+----------+-----------+-------------
    | 1     | 1        | 1        | 1        |           |
    | 2     | 1        | 2        | 2        |           |
    +-------+----------+----------+----------+-----------+-------------

idINT(11) UNSIGNED NOT NULL AUTO_INCREMENT

id_filesINT(11) 非空,

id_userINT(11) 非空,

id_diskINT(11) 非空,

主键 (id,id_files,id_user,id_disk) 索引fk_files_on_nas_idx (id ASC)

约束fk_files_on_nas

外键(id_files,id_user,id_disk

参考database.FILES (id,id_user, id_disk)

不删除任何操作

更新无操作)

问题:

如您所见,我在级联中引用的表越多,我得到的主键就越多。如何设计数据库以避免复制主键,从而避免数据重复?我应该删除每个表的自动递增键吗?这是一个好习惯吗?

谢谢

【问题讨论】:

【参考方案1】:

磁盘的 ID 足以唯一标识磁盘。所以没有理由将用户的 ID 包含在磁盘的主键中。这甚至是一个非常糟糕的主意,因为这意味着如果磁盘的用户发生变化,您将需要修改主键。

文件也一样。文件 ID 唯一标识一个文件。所以没有理由将磁盘 ID 添加到文件的主键中。

【讨论】:

我完全同意你的看法。我问这个问题的原因是因为当我使用 mysql Workbenck(EER 模型部分)创建生成 sql 文件的一对多关系时,软件将所有主键放入表中。我试图删除不必要的主键,但引擎不允许将模型转发到数据库中 我不知道 MySQL 工作台是如何工作的。我一般使用 PostgreSQL,我直接使用 SQL 创建表。 我过去使用过 MySQL Workbench,但我不记得遇到过这个问题......但我现在使用的是 SQLYog,所以我真的不知道。 您可能没有正确执行此操作,因为它没有理由从这样的外键中生成主键。 我按照您的最佳实践解决了我的问题。我在 gedit 文档中手动删除了这些字段,并将其粘贴到 mysql 控制台后,我运行脚本没有问题。软件有些奇怪,导致我创建了不必要的主键【参考方案2】:

我强烈建议不要删除自动递增的键。

但是你不需要每次都创建一个新的主键:

如果您希望多个用户共享一个磁盘,只需在 USERS 中放入id_disk外键 如果您希望一个用户可以拥有多个磁盘,则在 DISKS 中放置一个 外键 id_user

只有在遇到 多对多 关系时才使用这样的主键。在这种情况下,您需要创建一个新表来连接两个表;将两个表的主键作为外键,形成一个耦合的主键,就像你做的那样。

【讨论】:

非常感谢,这很有帮助【参考方案3】:

您可能想了解一下Database Normalization。在您的情况下,我会将 surrogate key id 设为表中唯一的主键。比如:

create table users (
    id integer not null auto_increment,
    username varchar(50),
    ...,
    primary key (id)
);

create table disks (
    id integer not null auto_increment,
    user_id integer,
    diskname varchar(50),
    ....,
    primary key (id),
    foreign key (user_id) references users (id)
);

对于files,您将不得不回答这个问题:文件所有权是直接依赖于文件,还是传递地依赖于磁盘所有权,还是所有权独立?杰克拥有的磁盘上的约翰拥有的文件?对我来说似乎没问题,但您的域可能有不同的规则。在这种情况下,请从 files 表中删除 user_id(否则您的数据库将不在 Third normal form 中)。

create table files (
    id integer not null auto_increment,
    disk_id integer,
    user_id integer, -- you have to decide whether this is necessary
    filename varchar(50),
    ....,
    primary key (id),
    foreign key (disk_id) references disks (id),
    foreign key (user_id) references users (id)
);

【讨论】:

非常感谢您的帮助

以上是关于使用生成的主键引用表的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL 脚本中引用生成的主键

如何将自动生成的主键复制到另一个表中

替换其他表中作为外键的主键

javaWeb_JDBC_JDBC获取数据库自动生成的主键值

flea-db使用之主键生成器表介绍

Oracle数据库中序列(SEQUENCE)的用法详解