关系型数据库经常使用多表查询,
- 假如我们的上面的商品表中,对应的品牌还需要包含其他的信息:
- 比如品牌的官网,品牌的世界排名,品牌的市值等等;
- 如果我们直接在商品中去体现品牌相关的信息,会存在一些问题:
- 一方面,products表中应该表示的都是商品相关的数据,应该有另外一张表来表示brand的数据;
- 另一方面,多个商品使用的品牌是一致时,如果全部放在一张表里,会产生大量的冗余数据;
创建一张新表
CREATE TABLE IF NOT EXISTS `brand` (id INT PRIMARY KEY AUTO_INCREMENT,`name` VARCHAR(20),`website` VARCHAR(100),`phoneRank` INT);# 添加字段INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('小米', 'https://www.xiaomi.com', 2);INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('苹果', 'https://www.apple.com', 1);INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('华为', 'https://www.huawei.com', 8);INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('OPPO', 'https://www.oppo.com', 5);INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('SUMSUNG', 'https://www.sumsung.com', 4);INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('winphone', 'https://www.winphone.com', 134);
外键
【理解:外键是对当前字段范围的一种约束】。
[CONSTRAINT <外键名>] FOREIGN KEY 字段名 [,字段名2,…]
REFERENCES <主表名> 主键列1 [,主键列2,…]
给products表中添加一个字段:brand_id,以便和brand表产生关系。
但brand_id不能为任意值,它取值的集合必须是表brand中id集合的子集。
所以如何设置外键?
方法一:创建products表时绑定外键
CREATE TABLE IF NOT EXISTS `products` (
id INT PRIMARY KEY AUTO_INCREMENT,
brand VARCHAR ( 20 ),
title VARCHAR ( 100 ) NOT NULL,
price DOUBLE NOT NULL,
score DECIMAL ( 2, 1 ),
voteCnt INT,
url VARCHAR ( 100 ),
pid INT -- product id,
FOREIGN KEY (brand_id) REFERENCES brand(id) -- 外键
);
方法二:添加brand_id字段,并修改brand_id为外键
# 添加brand_id字段
ALTER TABLE `products` ADD `brand_id` INT;
# 修改brand_id为外键
ALTER TABLE `products` ADD FOREIGN KEY(brand_id) REFERENCES brand(id);
右键products表,点击Design Table,查看foreign key:
到这里,先把部分手机品牌对应brand_id设置成正确的值,完成测试数据。
UPDATE `products` SET brand_id = 1 WHERE brand = '小米';
UPDATE `products` SET brand_id = 2 WHERE brand = '苹果';
UPDATE `products` SET brand_id = 3 WHERE brand = '华为';
UPDATE `products` SET brand_id = 4 WHERE brand = 'OPPO';
问题
如果products中引用的外键被删除或者更新了,这个时候会出现什么情况?
UPDATE `brand` SET id = 100 WHERE id = 1;
# 报错,不能修改,
# 1451 - Cannot delete or update a parent row: a foreign key constraint
如果我希望可以更新呢?
那就需要修改on delete或者on update的值;
我们可以给更新或者删除时设置几个值::
- RESTRICT(默认属性):当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话会报错的, 不允许更新或删除,【理解:简单点说,这对于实例的情况,删除或更新 为外键字段 提供范围的外部表主键会报错,当然修改当前表的外键字段是没事的,只要满足范围就行】;
- NO ACTION:和RESTRICT是一致的,是在SQL标准中定义的,相当于RESTRICT是MySQL对NO ACTION的实现;
- CASCADE:当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话:
- 更新:那么会更新对应的记录;
- 删除:那么关联的记录会被一起删除掉,这个一般不设置关联,属于危险操作;
- 【理解:修改或删除了
brand表中被外键关联的id值,外键字段的值会跟随变化】;
- SET NULL:当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话,将对应的值设置为 NULL,【理解:修改或删除了
brand表中被外键关联的id值,外键字段的值会变成NULL】;
所以这里修改brand_id关联外键的方式为:
第一种在Navicat中直接操作
第二种:
# 通过此方法获取外键的名称[CONSTRAINT]
SHOW CREATE TABLE `products`;
/*
CREATE TABLE `products` (
`id` int NOT NULL AUTO_INCREMENT,
`brand` varchar(20) DEFAULT NULL,
`title` varchar(100) NOT NULL,
`price` double NOT NULL,
`score` decimal(2,1) DEFAULT NULL,
`voteCnt` int DEFAULT NULL,
`url` varchar(100) DEFAULT NULL,
`pid` int DEFAULT NULL,
`brand_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `brand_id` (`brand_id`),
CONSTRAINT `products_ibfk_1` FOREIGN KEY (`brand_id`) REFERENCES `brand` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
*/
# 根据名称将外键删除掉, 查看效果需要关闭products的Design Table窗口再打开查看
ALTER TABLE `products` DROP FOREIGN KEY `products_ibfk_1`;
ALTER TABLE `products` DROP FOREIGN KEY `products_ibfk_2`;
# 重新添加外键约束, 查看效果需要关闭products的Design Table窗口再打开查看
ALTER TABLE `products` ADD FOREIGN KEY (brand_id) REFERENCES brand(id)
ON UPDATE CASCADE
ON DELETE RESTRICT;-- 也可省略,默认为RESTRICT
注意不要设置成删除关联,经测试,设置成删除关联,主键删除,外键对应的数据也会完全删除
