[英]MySQL - One To One Relationship?
我正在尝试在 MySQL 数据库中实现“一对一”关系。 例如,假设我有一个用户表和一个帐户表。 我想确保一个用户只能拥有一个帐户。 并且每个用户只能有一个帐户。
我为此找到了两种解决方案,但不知道该使用什么,还有其他选择吗?
DROP DATABASE IF EXISTS test;
CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci;
USE test;
CREATE TABLE users(
id INT NOT NULL AUTO_INCREMENT,
user_name VARCHAR(45) NOT NULL,
PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
CREATE TABLE accounts(
id INT NOT NULL AUTO_INCREMENT,
account_name VARCHAR(45) NOT NULL,
user_id INT UNIQUE,
PRIMARY KEY(id),
FOREIGN KEY(user_id) REFERENCES users(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
在这个例子中,我在 accounts 中定义外键指向 users 中的主键。 然后我将外键设置为唯一,因此帐户中不能有两个相同的用户。 要连接表,我将使用此查询:
SELECT * FROM users JOIN accounts ON users.id = accounts.user_id;
DROP DATABASE IF EXISTS test;
CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci;
USE test;
CREATE TABLE users(
id INT NOT NULL AUTO_INCREMENT,
user_name VARCHAR(45) NOT NULL,
PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
CREATE TABLE accounts(
id INT NOT NULL AUTO_INCREMENT,
account_name VARCHAR(45) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY(id) REFERENCES users(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
在此示例中,我创建了一个从主键指向另一个表中的主键的外键。 由于默认情况下主键是唯一的,因此这种关系是一对一的。 要加入表格,我可以使用这个:
SELECT * FROM users JOIN accounts ON users.id = accounts.id;
现在的问题:
我正在使用 MySQL Workbench,当我在 EER 图中设计一对一关系并让 MySQL Workbench 生成 SQL 代码时,我得到一对多关系:S 这让我感到困惑:S
如果我将这些解决方案中的任何一个导入 MySQL Workbench EER 图中,它会将关系识别为一对多:S 这也令人困惑。
那么,在 MySQL DDL 中定义一对一关系的最佳方式是什么。 有哪些选择可以实现这一目标?
由于默认情况下主键是唯一的,因此这种关系是一对一的。
不,这使得关系“一对零或一”。 那是你真正需要的吗?
如果是,那么您的“第二个解决方案”更好:
顺便说一句,您需要将accounts.id
设置为普通整数(不是自动递增)才能正常工作。
如果没有,请看下面...
在 MySQL 中创建一对一关系的最佳方法是什么?
嗯,“最好”是一个重载的词,但“标准”解决方案与任何其他数据库中的解决方案相同:将两个实体(在您的情况下为用户和帐户)放在同一个物理表中。
除了这两个还有其他解决方案吗?
理论上,您可以在两个 PK 之间创建循环 FK,但这将需要延迟约束来解决先有鸡还是先有蛋的问题,不幸的是,MySQL 不支持这种问题。
如果我将这些解决方案中的任何一个导入 MySQL Workbench EER 图中,它会将关系识别为一对多:S 这也令人困惑。
我对那个特定的建模工具没有太多的实践经验,但我猜这是因为它是“一对多”的,其中“多”边通过使其唯一而被限制在 1。 请记住,“许多”并不意味着“1 或许多”,它意味着“0 或许多”,因此“上限”版本真正意味着“0 或 1”。
1不仅是附加字段的存储费用,还有二级索引的存储费用。 并且由于您使用的 InnoDB 始终对表进行聚簇,因此请注意,聚簇表中的二级索引比基于堆的表中的二级索引更昂贵。
2 InnoDB 需要外键索引。
您的第一种方法在 accounts 表中创建两个候选键: id
和user_id
。
因此,我建议采用第二种方法,即使用外键作为主键。 这个:
下面的方法呢
创建表用户
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
在user_id
和account_id
上创建具有唯一索引的表帐户,与用户/帐户的外键关系以及user_id and account_id
上的主键
CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
创建表 user2account
CREATE TABLE `user2account` ( `user_id` int(11) NOT NULL, `account_id` int(11) NOT NULL, PRIMARY KEY (`user_id`,`account_id`), UNIQUE KEY `FK_account_idx` (`account_id`), UNIQUE KEY `FK_user_idx` (`user_id`), CONSTRAINT `FK_account` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`), CONSTRAINT `FK_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
虽然此解决方案在数据库中的占用空间最大,但也有一些优势。
user2account
方法主要用于定义多对多关系,但在user_id
和account_id
上添加 UNIQUE 约束将防止创建除一对一关系之外的其他关系。我在这个解决方案中看到的主要优点是您可以将工作划分到公司的不同代码层或部门
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.