多表联查
多表查询,也叫链接查询
数据环境
SHOW CREATE TABLE `emp`;
| emp | CREATE TABLE `emp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL COMMENT '用户名',
`age` tinyint(3) unsigned NOT NULL DEFAULT '18' COMMENT '年龄',
`sex` enum('男','女','保密') NOT NULL DEFAULT '保密' COMMENT '性别',
`addr` varchar(20) NOT NULL DEFAULT '北京',
`dep_id` tinyint(3) unsigned NOT NULL COMMENT '部门对应编号',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
SHOW CREATE TABLE `dep`;
| dep | CREATE TABLE `dep` (
`id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
`dep_name` varchar(50) NOT NULL,
`dep_desc` varchar(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `dep_name` (`dep_name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 |
SELECT * FROM emp;
+----+----------+-----+--------+--------+--------+
| id | username | age | sex | addr | dep_id |
+----+----------+-----+--------+--------+--------+
| 1 | tom | 20 | 保密 | 北京 | 1 |
| 2 | john | 23 | 保密 | 北京 | 2 |
| 3 | mike | 20 | 保密 | 北京 | 3 |
| 4 | rose | 23 | 保密 | 北京 | 2 |
| 5 | lili | 20 | 保密 | 北京 | 4 |
| 6 | oven | 23 | 保密 | 北京 | 1 |
+----+----------+-----+--------+--------+--------+
SELECT * FROM dep;
+----+-----------+--------------+
| id | dep_name | dep_desc |
+----+-----------+--------------+
| 1 | 技术部 | 研发 |
| 2 | 人事部 | 人事工作 |
| 3 | 财务部 | 财务工作 |
| 4 | 运营部 | 运营工作 |
+----+-----------+--------------+
-- 需求:查询 emp中的id,username,age dep表中的dep_name
复制代码
笛卡尔积的形式
-- 笛卡尔积的形式相当于两张表乘积
SELECT emp.id,emp.username,emp.age,dep.dep_name FROM emp,dep;
+----+----------+-----+-----------+
| id | username | age | dep_name |
+----+----------+-----+-----------+
| 1 | tom | 20 | 人事部 |
| 1 | tom | 20 | 技术部 |
| 1 | tom | 20 | 财务部 |
| 1 | tom | 20 | 运营部 |
| 2 | john | 23 | 人事部 |
| 2 | john | 23 | 技术部 |
| 2 | john | 23 | 财务部 |
| 2 | john | 23 | 运营部 |
| 3 | mike | 20 | 人事部 |
| 3 | mike | 20 | 技术部 |
| 3 | mike | 20 | 财务部 |
| 3 | mike | 20 | 运营部 |
| 4 | rose | 23 | 人事部 |
| 4 | rose | 23 | 技术部 |
| 4 | rose | 23 | 财务部 |
| 4 | rose | 23 | 运营部 |
| 5 | lili | 20 | 人事部 |
| 5 | lili | 20 | 技术部 |
| 5 | lili | 20 | 财务部 |
| 5 | lili | 20 | 运营部 |
| 6 | oven | 23 | 人事部 |
| 6 | oven | 23 | 技术部 |
| 6 | oven | 23 | 财务部 |
| 6 | oven | 23 | 运营部 |
+----+----------+-----+-----------+
24 rows in set (0.00 sec)
复制代码
内连接的形式
查询两个表中符合连接条件的记录(取交集)
语法:SELECT 字段名称,... FROM 表名1 INNER JOIN 表名2 ON 连接条件 INNER JOIN 表名3 ON 连接条件...;(INNER 可以省略)
SELECT e.id,e.username,e.age,d.dep_name
FROM emp AS e
INNER JOIN dep AS d
ON e.dep_id = d.id;
+----+----------+-----+-----------+
| id | username | age | dep_name |
+----+----------+-----+-----------+
| 1 | tom | 20 | 技术部 |
| 2 | john | 23 | 人事部 |
| 3 | mike | 20 | 财务部 |
| 4 | rose | 23 | 人事部 |
| 5 | lili | 20 | 运营部 |
| 6 | oven | 23 | 技术部 |
+----+----------+-----+-----------+
复制代码
外链接的形式
INSERT dep SET dep_name='法务部',dep_desc='法务工作';
INSERT emp SET username='nico',age=19,dep_id=10;
复制代码
左外连接
先显示左表中的全部记录,再去右表中查询符合条件的记录,不符合的以NULL代替
语法:SELECT 字段名,... FROM 表名1 LEFT OUTER JOIN 表名2 ON 条件;(OUTER 可省略)
SELECT e.id,e.username,e.age,d.dep_name,d.dep_desc
FROM emp AS e
LEFT OUTER JOIN dep AS d
ON e.dep_id = d.id;
+----+----------+-----+-----------+--------------+
| id | username | age | dep_name | dep_desc |
+----+----------+-----+-----------+--------------+
| 1 | tom | 20 | 技术部 | 研发 |
| 6 | oven | 23 | 技术部 | 研发 |
| 2 | john | 23 | 人事部 | 人事工作 |
| 4 | rose | 23 | 人事部 | 人事工作 |
| 3 | mike | 20 | 财务部 | 财务工作 |
| 5 | lili | 20 | 运营部 | 运营工作 |
| 7 | nico | 19 | NULL | NULL |
+----+----------+-----+-----------+--------------+
复制代码
右外连接
先显示右表中的全部记录,再去左表中查询符合条件的记录,不符合的以NULL代替
语法:SELECT 字段名,... FROM 表名1 RIGHT OUTER JOIN 表名2 ON 条件;(OUTER 可省略)
SELECT e.id,e.username,e.age,d.dep_name,d.dep_desc
FROM emp AS e
RIGHT OUTER JOIN dep AS d
ON e.dep_id = d.id;
+------+----------+------+-----------+--------------+
| id | username | age | dep_name | dep_desc |
+------+----------+------+-----------+--------------+
| 1 | tom | 20 | 技术部 | 研发 |
| 2 | john | 23 | 人事部 | 人事工作 |
| 3 | mike | 20 | 财务部 | 财务工作 |
| 4 | rose | 23 | 人事部 | 人事工作 |
| 5 | lili | 20 | 运营部 | 运营工作 |
| 6 | oven | 23 | 技术部 | 研发 |
| NULL | NULL | NULL | 法务部 | 法务工作 |
+------+----------+------+-----------+--------------+
复制代码
外键约束
只有INNODB存储引擎支持外键约束
- 建表时指定外键
语法: [CONSTRAINT 外键名称]FOREIGH KEY (字段名) REFERENCES 表名(字段名); 外键名称可省略
子表的外键字段和父表字段类型要相似,如果是数值型要求一致,有无符号位也要一致,如果是字符型,要求类型一致,长度可以不同
如果外键字段没有创建索引,mysql会自动添加一个普通索引
子表的外键关联的必须是父表的主键
-- 创建父表
CREATE TABLE `news_cate` (
`id` TINYINT (3) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '编号',
`cateName` VARCHAR (50) NOT NULL COMMENT '分类名称',
`cateDesc` VARCHAR (100) NOT NULL DEFAULT '' COMMENT '分类描述',
PRIMARY KEY (`id`),
UNIQUE KEY `cate_name` (`cateName`)
) ENGINE = INNODB DEFAULT CHARSET = utf8;
-- 创建子表
CREATE TABLE `news` (
`id` INT (10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '编号',
`title` VARCHAR (100) NOT NULL COMMENT '新闻标题',
`content` VARCHAR (1000) NOT NULL COMMENT '新闻内容',
`cateId` TINYINT (3) UNSIGNED NOT NULL COMMENT '新闻所属分类id',
PRIMARY KEY (`id`),
UNIQUE KEY `title` (`title`),
CONSTRAINT cateId__fk__news_cate FOREIGN KEY (`cateId`) REFERENCES `news_cate` (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8;
-- 插入数据
INSERT news_cate (cateName)
VALUES
('国内新闻'),
('国际新闻'),
('娱乐新闻'),
('体育新闻');
INSERT news (title, content, cateId)
VALUES
('a1', 'aaaa1', 1),
('a2', 'aaaa2', 1),
('a3', 'aaaa3', 4),
('a4', 'aaaa4', 2),
('a5', 'aaaa5', 3);
-- 当插入数据不符合要求时报错
INSERT news (title, content, cateId) VALUES ('a10', 'aaaa10', 10);
ERROR 1452 (23000):Cannot add or update a child row: a foreign key constraint fails (`test`.`news`, CONSTRAINT `cateId__fk__news_cate` FOREIGN KEY (`cateId`) REFERENCES `news_cate` (`id`))
-- 删除父表或父表中的记录时,要确保被删除的内容没有被子表引用,有则先删除子表中的引用再做删除
-- 修改父表中的id时,要确保被修改的id没有被子表引用,有则先删除子表中的引用在做修改
复制代码
- 动态删除、添加外键
删除外键 :ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
ALTER TABLE news DROP FOREIGN KEY cateId__fk__news_cate;
SHOW CREATE TABLE news;
+-----------------------------------------------------------------------
CREATE TABLE `news` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
`title` varchar(100) NOT NULL COMMENT '新闻标题',
`content` varchar(1000) NOT NULL COMMENT '新闻内容',
`cateId` tinyint(3) unsigned NOT NULL COMMENT '新闻所属分类id',
PRIMARY KEY (`id`),
UNIQUE KEY `title` (`title`),
KEY `cateId__fk__news_cate` (`cateId`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
+-----------------------------------------------------------------------
复制代码
添加外键 :ALTER TABLE 表名 ADD FOREIGN KEY (外键字段名) REFERENCES 父表(主键字段名);
动态添加外键需要确保表中记录是合法的
ALTER TABLE news ADD CONSTRAINT cateId__fk__news_cate FOREIGN KEY (cateId) REFERENCES news_cate (id);
SHOW CREATE TABLE news;
+-----------------------------------------------------------------------
CREATE TABLE `news` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
`title` varchar(100) NOT NULL COMMENT '新闻标题',
`content` varchar(1000) NOT NULL COMMENT '新闻内容',
`cateId` tinyint(3) unsigned NOT NULL COMMENT '新闻所属分类id',
PRIMARY KEY (`id`),
UNIQUE KEY `title` (`title`),
KEY `cateId__fk__news_cate` (`cateId`),
CONSTRAINT `cateId__fk__news_cate` FOREIGN KEY (`cateId`) REFERENCES `news_cate` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
+-----------------------------------------------------------------------
复制代码
外键约束的参照操作
- CASCADE 级联操作 从父表中删除或者更新,子表也跟着删除或者更新
- SET NULL 从父表中删除或更新记录,并设置字表的外键列为NULL 需要取消该列NOT NULL 约束
- NO ACTION | RESTRICT 拒绝父表做更新和删除操作(默认)
语法: [CONSTRAINT 外键名称]FOREIGH KEY (字段名) REFERENCES 表名(字段名) ON DELET CASCADE ON UPDATE CASCADE;