我正在尝试在MySQL数据库中实现One To One关系。例如,假设我有Users表和Accounts表。我想确定用户只能拥有一个帐户。并且每个用户只能有一个帐户。
我找到了两个解决方案,但不知道该使用什么,还有其他选择。
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;
在此示例中,我在指向用户主键的帐户中定义外键。 然后我将外键设为UNIQUE,因此帐户中不能有两个相同的用户。 要连接表,我会使用此查询:
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;
在此示例中,我创建了一个外键,该外键从主键指向另一个表中的主键。由于主键默认为UNIQUE,因此这种关系一对一。 要连接表格,我可以使用:
SELECT * FROM users JOIN accounts ON users.id = accounts.id;
现在问题:
我正在使用MySQL Workbench,当我在EER图中设计One To One关系并让MySQL Workbench生成SQL代码时,我得到了一对多关系:S这让我感到困惑:S
如果我将这些解决方案中的任何一个导入到MySQL Workbench EER图表中,它会将关系视为一对多:S这也令人困惑。
那么,在MySQL DDL中定义一对一关系的最佳方法是什么。有什么选择可以实现这个目标?
答案 0 :(得分:40)
由于主键默认为UNIQUE,因此这种关系是一对一的。
不,这使得关系“一到零或一”。那是你真正需要的吗?
如果是,那么您的“第二个解决方案”会更好:
顺便说一下,你需要让accounts.id
成为一个普通的整数(不是自动增量)才能生效。
如果否,请参阅以下内容......
在MySQL中创建一对一关系的最佳方法是什么?
嗯,“最好”是一个重载词,但“标准”解决方案与任何其他数据库中的相同:将两个实体(用户和帐户都在你的情况下)放在同一个物理表中。
除了这两种解决方案之外还有其他解决方案吗?
理论上,你可以在两个PK之间制作循环FK,但这需要 deferred 约束来解决鸡与蛋的问题,遗憾的是MySQL不支持这个问题。
如果我将这些解决方案中的任何一个导入到MySQL Workbench EER图中,它会将关系视为一对多:这也是令人困惑的。
我对这个特定的建模工具没有太多的实际经验,但我猜这是因为它是“一对多”,其中“很多”方面通过使其独特而被限制为1。请记住,“很多”并不代表“1或多”,它的意思是“0或许多”,所以“上限”版本的确意味着“0或1”。
1 不仅在附加字段的存储费用中,而且在二级索引中也是如此。因为您正在使用always clusters tables的InnoDB,请注意,在集群表中,二级索引比在基于堆的表中更昂贵。
外键上的2 InnoDB requires indexes。
答案 1 :(得分:8)
您的第一种方法是在帐户表格中创建两个候选键:id
和user_id
。
答案 2 :(得分:-2)
以下方法如何
创建表用户
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约束会阻止创建除一对一关系之外的其他关系我在此解决方案中看到的主要优势是您可以在公司的不同代码层或部门中划分工作