关系型数据库经常使用多表查询,

  • 假如我们的上面的商品表中,对应的品牌还需要包含其他的信息:
    • 比如品牌的官网,品牌的世界排名,品牌的市值等等;
  • 如果我们直接在商品中去体现品牌相关的信息,会存在一些问题:
    • 一方面,products表中应该表示的都是商品相关的数据,应该有另外一张表来表示brand的数据;
    • 另一方面,多个商品使用的品牌是一致时,如果全部放在一张表里,会产生大量的冗余数据;

所以可以将品牌数据单独放在一张表里。

创建一张新表

  1. CREATE TABLE IF NOT EXISTS `brand` (
  2. id INT PRIMARY KEY AUTO_INCREMENT,
  3. `name` VARCHAR(20),
  4. `website` VARCHAR(100),
  5. `phoneRank` INT
  6. );
  7. # 添加字段
  8. INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('小米', 'https://www.xiaomi.com', 2);
  9. INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('苹果', 'https://www.apple.com', 1);
  10. INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('华为', 'https://www.huawei.com', 8);
  11. INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('OPPO', 'https://www.oppo.com', 5);
  12. INSERT INTO `brand` (`name`, `website`, `phoneRank`) VALUES('SUMSUNG', 'https://www.sumsung.com', 4);
  13. 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:
image.png
到这里,先把部分手机品牌对应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';

image.png

问题

如果products中引用的外键被删除或者更新了,这个时候会出现什么情况?

UPDATE `brand` SET id = 100 WHERE id = 1;
# 报错,不能修改,
# 1451 - Cannot delete or update a parent row: a foreign key constraint

观察products属性
image.png

如果我希望可以更新呢?

那就需要修改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

注意不要设置成删除关联,经测试,设置成删除关联,主键删除,外键对应的数据也会完全删除