1.外键的约束
#建一张表 id 员工的名字 员工部门 创建时间 mysql> use javadd; Database changed mysql> create table employee ( -> id int primary key auto_increment, -> emp_name varchar(32) not null, -> dept_name varchar(32) not null, -> create_time timestamp default current_timestamp -> ); Query OK, 0 rows affected (0.01 sec) mysql> insert into employee (emp_name, dept_name) values("11", "教学部"); Query OK, 1 row affected (0.02 sec) mysql> insert into employee (emp_name, dept_name) values("22", "教学部"); Query OK, 1 row affected (0.00 sec) mysql> insert into employee (emp_name, dept_name) values("33", "品保部"); Query OK, 1 row affected (0.00 sec) mysql> insert into employee (emp_name, dept_name) values("44", "品保部"); Query OK, 1 row affected (0.00 sec) mysql> insert into employee (emp_name, dept_name) values("55", "技术部"); Query OK, 1 row affected (0.00 sec) mysql> select * from employee; +----+----------+-----------+---------------------+ | id | emp_name | dept_name | create_time | +----+----------+-----------+---------------------+ | 1 | 11 | 教学部 | 2023-04-10 09:20:42 | | 2 |22 | 教学部 | 2023-04-10 09:20:51 | | 3 |33 | 品保部 | 2023-04-10 09:21:36 | | 4 | 44 | 品保部 | 2023-04-10 09:21:44 | | 5 | 55 | 技术部 | 2023-04-10 09:22:20 | +----+----------+-----------+---------------------+ #这种设计表是有问题的,部门的数据是冗余的,这样是不好的,必须拆开两个表,一个员工表 一个部门表
# mysql> create table dept ( -> dept_id int primary key auto_increment, -> dept_name varchar(32) -> ); Query OK, 0 rows affected (0.01 sec) mysql> create table emp ( -> emp_id int primary key auto_increment, -> emp_name varchar(32) , -> dept_id int, -> reg_time timestamp default current_timestamp -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into dept(dept_name) values("教学部"); Query OK, 1 row affected (0.00 sec) mysql> insert into dept(dept_name) values("品保部"); Query OK, 1 row affected (0.01 sec) mysql> insert into dept(dept_name) values("技术部"); Query OK, 1 row affected (0.00 sec) mysql> insert into emp (emp_name, dept_id) values ("lag", 1); Query OK, 1 row affected (0.01 sec) mysql> insert into emp (emp_name, dept_id) values ("sl", 1); Query OK, 1 row affected (0.00 sec) mysql> insert into emp (emp_name, dept_id) values ("eb", 2); Query OK, 1 row affected (0.00 sec) mysql> insert into emp (emp_name, dept_id) values ("ej", 2); Query OK, 1 row affected (0.00 sec) mysql> insert into emp (emp_name, dept_id) values ("js", 3); Query OK, 1 row affected (0.00 sec) mysql> select * from dept; +---------+-----------+ | dept_id | dept_name | +---------+-----------+ | 1 | 教学部 | | 2 | 品保部 | | 3 | 技术部 | +---------+-----------+ 3 rows in set (0.00 sec) mysql> select * from emp; +--------+----------+---------+---------------------+ | emp_id | emp_name | dept_id | reg_time | +--------+----------+---------+---------------------+ | 1 | laoxing | 1 | 2023-04-10 09:39:49 | | 2 | sl | 1 | 2023-04-10 09:39:55 | | 3 | eb | 2 | 2023-04-10 09:40:09 | | 4 | ej | 2 | 2023-04-10 09:40:13 | | 5 | js | 3 | 2023-04-10 09:40:19 | +--------+----------+---------+---------------------+ #插入一个数据: 要求插入员工数据,但是需要写dept_id 写一个没有的部门id 8 能插入成功不? #可以插入成功不。需求开发场景不合适 mysql> insert into emp (emp_name, dept_id) values("gd", 8); Query OK, 1 row affected (0.00 sec) #删除一个部门的话: 如果我将一个部门删除技术部,真实的需求的时候 删除一个部门,部门下面所对应也要全部删除 mysql> delete from dept where dept_id = 3; Query OK, 1 row affected (0.00 sec) mysql> select * from emp; +--------+----------+---------+---------------------+ | emp_id | emp_name | dept_id | reg_time | +--------+----------+---------+---------------------+ | 1 | lng | 1 | 2023-04-10 09:39:49 | | 2 | sl | 1 | 2023-04-10 09:39:55 | | 3 | eb | 2 | 2023-04-10 09:40:09 | | 4 | ej | 2 | 2023-04-10 09:40:13 | | 5 | js | 3 | 2023-04-10 09:40:19 | | 6 | gd | 8 | 2023-04-10 09:42:13 | +--------+----------+---------+---------------------+ #添加员工的时候,随便可以添加,尽管这个部门不存在,删除一个部门。部门下面的员工也还在。这些都是实际开发中不合理的,造成不合理的原因,这两张表是没有关系的!!! #咋让两张表产生关系呢? 使用外键
mysql> create table emp ( -> emp_id int primary key auto_increment, -> emp_name varchar(32) , -> dept_id int, -> reg_time timestamp default current_timestamp, #constraint 约束的意思 #fk_emp_dept 外键的名字 随意起 #foreign key(dept_id) 外键 使用本表中的一个字段作为外键去和别的表产生关系 #references 关联 引用的意思,去关联主表里面的某一个字段(外键所在的表叫副表) -> constraint fk_emp_dept foreign key(dept_id) references dept(dept_id) -> ); Query OK, 0 rows affected (0.09 sec) mysql> drop table emp; Query OK, 0 rows affected (0.01 sec) mysql> select * from dept; +---------+-----------+ | dept_id | dept_name | +---------+-----------+ | 1 | 教学部 | | 2 | 品保部 | +---------+-----------+ #插入数据 mysql> insert into emp (emp_name, dept_id) values("lx", 1); Query OK, 1 row affected (0.01 sec) mysql> insert into emp (emp_name, dept_id) values("sl", 1); Query OK, 1 row affected (0.00 sec) #插入了一个不存在的部门 的时候结果报错课 mysql> insert into emp (emp_name, dept_id) values("gd", 4); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`java2304`.`emp`, CONSTRAINT `fk_emp_dept` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`dept_id`)) #删除数据 删除教学部 mysql> delete from dept where dept_id = 1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`java2304`.`emp`, CONSTRAINT `fk_emp_dept` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`dept_id`)) #修改数据 mysql> update dept set dept_id = 5 where dept_id = 1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`java2304`.`emp`, CONSTRAINT `fk_emp_dept` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`dept_id`)) mysql> #加上外键约束以后,增删改 有的时候会报错 #主表(部门表) 副表(员工表) #增加的时候: 先看主表 然后增加副表 #删除的时候: 先删除副表 再删除主表 #修改的时候: 先修改副表 再修改主表 #这样才能不报错 #太麻烦了,还得记这些 #级联操作!!! 级联修改 和级联删除 mysql> drop table emp; Query OK, 0 rows affected (0.01 sec) mysql> create table emp ( -> emp_id int primary key auto_increment, -> emp_name varchar(32) , -> dept_id int, -> reg_time timestamp default current_timestamp, -> constraint fk_emp_dept foreign key(dept_id) references dept(dept_id) #加的两个状态 -> on delete cascade -> on update cascade -> ); Query OK, 0 rows affected (0.01 sec) mysql> delete from dept where dept_id =1; Query OK, 1 row affected (0.01 sec) mysql> select * from emp; +--------+----------+---------+---------------------+ | emp_id | emp_name | dept_id | reg_time | +--------+----------+---------+---------------------+ | 3 | xueke | 2 | 2023-04-10 10:46:04 | | 4 | erbei | 2 | 2023-04-10 10:46:08 | | 5 | erjia | 2 | 2023-04-10 10:46:11 | +--------+----------+---------+---------------------+ #修改: mysql> update dept set dept_id = 4 where dept_id =2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from emp; +--------+----------+---------+---------------------+ | emp_id | emp_name | dept_id | reg_time | +--------+----------+---------+---------------------+ | 3 | xueke | 4 | 2023-04-10 10:46:04 | | 4 | erbei | 4 | 2023-04-10 10:46:08 | | 5 | erjia | 4 | 2023-04-10 10:46:11 | +--------+----------+---------+---------------------+ 真实开发的时候,特别是外键约束的表的时候,要加上级联删除和级联修改 mysql> create table emp ( -> emp_id int primary key auto_increment, -> emp_name varchar(32) , -> dept_id int, -> reg_time timestamp default current_timestamp, -> constraint fk_emp_dept foreign key(dept_id) references dept(dept_id) #加的两个状态 -> on delete cascade -> on update cascade -> );
2.联表查询【重点】
2.1常规的联表查询
#增删改和外键约束有关 查询没有关系的 mysql> select * from dept; +---------+-----------+ | dept_id | dept_name | +---------+-----------+ | 4 | 品保部 | | 5 | 教学部 | | 6 | 技术部 | +---------+-----------+ 3 rows in set (0.00 sec) mysql> select * from emp; +--------+----------+---------+---------------------+ | emp_id | emp_name | dept_id | reg_time | +--------+----------+---------+---------------------+ | 3 | xue | 4 | 2023-04-10 10:46:04 | | 4 | erbei | 4 | 2023-04-10 10:46:08 | | 5 | erjia | 4 | 2023-04-10 10:46:11 | | 6 | 东哥 | 5 | 2023-04-10 11:00:59 | | 7 | 飞哥 | 5 | 2023-04-10 11:01:11 | +--------+----------+---------+---------------------+ #联表查询 查看 erbei 属于哪个部门 select emp.emp_name, dept.dept_name # 查什么 from emp, dept #从哪查 where emp.dept_id = dept.dept_id and emp.emp_name = "erbei" #查询的条件 mysql> select * -> from emp, dept -> where emp.dept_id = dept.dept_id; +--------+----------+---------+---------------------+---------+-----------+ | emp_id | emp_name | dept_id | reg_time | dept_id | dept_name | +--------+----------+---------+---------------------+---------+-----------+ | 3 | xueke | 4 | 2023-04-10 10:46:04 | 4 | 品保部 | | 4 | e3 | 4 | 2023-04-10 10:46:08 | 4 | 品保部 | | 5 | erjia | 4 | 2023-04-10 10:46:11 | 4 | 品保部 | | 6 | 东哥 | 5 | 2023-04-10 11:00:59 | 5 | 教学部 | | 7 | 飞哥 | 5 | 2023-04-10 11:01:11 | 5 | 教学部 | +--------+----------+---------+---------------------+---------+-----------+ 5 rows in set (0.01 sec) mysql> select * -> from emp, dept -> where emp.dept_id = dept.dept_id and emp.emp_name = "erbei"; +--------+----------+---------+---------------------+---------+-----------+ | emp_id | emp_name | dept_id | reg_time | dept_id | dept_name | +--------+----------+---------+---------------------+---------+-----------+ | 4 | erbei | 4 | 2023-04-10 10:46:08 | 4 | 品保部 | +--------+----------+---------+---------------------+---------+-----------+ 1 row in set (0.00 sec) mysql> select emp.emp_name, dept.dept_name -> from emp, dept -> where emp.dept_id = dept.dept_id and emp.emp_name = "erbei"; +----------+-----------+ | emp_name | dept_name | +----------+-----------+ | erbei | 品保部 | +----------+-----------+ 1 row in set (0.00 sec) #对表起表名 select e.emp_name, d.dept_name from emp e, dept d where e.dept_id = d.dept_id and e.emp_name = "erbei"; mysql> select e.emp_name as "员工名字", d.dept_name as "部门名字" -> from emp e, dept d -> where e.dept_id = d.dept_id and e.emp_name = "erbei"; +----------+-----------+ | emp_name | dept_name | +----------+-----------+ | erbei | 品保部 | +----------+-----------+ 1 row in set (0.00 sec) #找出教学部有有哪些人 select d.dept_name, e.emp_name from dept d, emp e where d.dept_id = e.dept_id and d.dept_name= "教学部"; mysql> select d.dept_name, e.emp_name -> from dept d, emp e -> where d.dept_id = e.dept_id and d.dept_name= "教学部"; +-----------+----------+ | dept_name | emp_name | +-----------+----------+ | 教学部 | 东哥 | | 教学部 | 飞哥 | +-----------+----------+ 2 rows in set (0.00 sec)
2.2内连接和外连接
也是牵涉多表联查,只不过换了一种写法而已
2.2.1内连接
SELECT column_name(s) 查什么 FROM table_name1 从哪查 表1 INNER JOIN table_name2 关联 表2 ON table_name1.column_name=table_name2.column_name注释:INNER JOIN 与 JOIN 是相同的。
mysql> select * from dept; +---------+-----------+ | dept_id | dept_name | +---------+-----------+ | 4 | 品保部 | | 5 | 教学部 | | 6 | 技术部 | +---------+-----------+ 3 rows in set (0.00 sec) mysql> select * from emp; +--------+----------+---------+---------------------+ | emp_id | emp_name | dept_id | reg_time | +--------+----------+---------+---------------------+ | 3 | xueke | 4 | 2023-04-10 10:46:04 | | 4 | erbei | 4 | 2023-04-10 10:46:08 | | 5 | erjia | 4 | 2023-04-10 10:46:11 | | 6 | 东哥 | 5 | 2023-04-10 11:00:59 | | 7 | 飞哥 | 5 | 2023-04-10 11:01:11 | +--------+----------+---------+---------------------+ select e.emp_name, d.dept_name from emp e inner join dept d on e.dept_id = d.dept_id where e.emp_name = "erjia"; mysql> select * -> from emp -> inner join dept -> on emp.dept_id = dept.dept_id -> where emp.emp_name = "erjia"; +--------+----------+---------+---------------------+---------+-----------+ | emp_id | emp_name | dept_id | reg_time | dept_id | dept_name | +--------+----------+---------+---------------------+---------+-----------+ | 5 | erjia | 4 | 2023-04-10 10:46:11 | 4 | 品保部 | +--------+----------+---------+---------------------+---------+-----------+ 1 row in set (0.01 sec) mysql> select emp.emp_name, dept.dept_name -> from emp -> inner join dept -> on emp.dept_id = dept.dept_id -> where emp.emp_name = "erjia"; +----------+-----------+ | emp_name | dept_name | +----------+-----------+ | erjia | 品保部 | +----------+-----------+ 1 row in set (0.00 sec) mysql> select e.emp_name, d.dept_name #查什么 -> from emp e #从第一个表 -> inner join dept d #关联第二表 -> on e.dept_id = d.dept_id #表之间的连接的字段 -> where e.emp_name = "erjia"; #条件 +----------+-----------+ | emp_name | dept_name | +----------+-----------+ | erjia | 品保部 | +----------+-----------+ 1 row in set (0.00 sec) #查 品保部的人 mysql> select d.dept_name, e.emp_name -> from dept d -> join emp e -> on d.dept_id = e.dept_id -> where d.dept_name= "品保部"; +-----------+----------+ | dept_name | emp_name | +-----------+----------+ | 品保部 | xueke | | 品保部 | erbei | | 品保部 | erjia | +-----------+----------+
2.2.2外连接【开发中用的很少】
#左外连接 和右外连接 #LEFT JOIN 关键字会从左表 (table_name1) 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行。 mysql> select * -> from dept d -> left outer join emp e -> on d.dept_id = e.dept_id; +---------+-----------+--------+----------+---------+---------------------+ | dept_id | dept_name | emp_id | emp_name | dept_id | reg_time | +---------+-----------+--------+----------+---------+---------------------+ | 4 | 品保部 | 3 | xueke | 4 | 2023-04-10 10:46:04 | | 4 | 品保部 | 4 | erbei | 4 | 2023-04-10 10:46:08 | | 4 | 品保部 | 5 | erjia | 4 | 2023-04-10 10:46:11 | | 5 | 教学部 | 6 | 东哥 | 5 | 2023-04-10 11:00:59 | | 5 | 教学部 | 7 | 飞哥 | 5 | 2023-04-10 11:01:11 | | 6 | 技术部 | NULL | NULL | NULL | NULL | | 7 | 总经办 | NULL | NULL | NULL | NULL | +---------+-----------+--------+----------+---------+---------------------+ #RIGHT JOIN 关键字会右表 (table_name2) 那里返回所有的行,即使在左表 (table_name1) 中没有匹配的行。 mysql> select * -> from emp e -> right outer join dept d -> on e.dept_id = d.dept_id; +--------+----------+---------+---------------------+---------+-----------+ | emp_id | emp_name | dept_id | reg_time | dept_id | dept_name | +--------+----------+---------+---------------------+---------+-----------+ | 3 | xueke | 4 | 2023-04-10 10:46:04 | 4 | 品保部 | | 4 | erbei | 4 | 2023-04-10 10:46:08 | 4 | 品保部 | | 5 | erjia | 4 | 2023-04-10 10:46:11 | 4 | 品保部 | | 6 | 东哥 | 5 | 2023-04-10 11:00:59 | 5 | 教学部 | | 7 | 飞哥 | 5 | 2023-04-10 11:01:11 | 5 | 教学部 | | NULL | NULL | NULL | NULL | 6 | 技术部 | | NULL | NULL | NULL | NULL | 7 | 总经办 | +--------+----------+---------+---------------------+---------+-----------+ 7 rows in set (0.00 sec)
上午的内容
1.外键约束 在创建表的时候,本表中的一个字段h会作为另外一个表的的外键 让两个表有关系 constraint 外键名字(自定义的) foreign key(本表字段) references 另外一张表(字段) on delete cascade on update cascade; 2.多表联查 常规写法: select * from emp, dept where emp.dept_id = dept.dept_id 内连接: select * from emp inner join dept on emp.dept_id = dept.dept_id 左外连接: select * from emp left outer join dept on emp.dept_id = dept.dept_id 右外连接
3.开发中如何使用多表联查
3.1一对多或者多对一 的查询
mysql> create table teacher ( -> t_id int primary key auto_increment, -> t_name varchar(32) -> ); Query OK, 0 rows affected (0.02 sec) mysql> create table student( -> s_id int primary key auto_increment, -> s_name varchar(32), -> teacher_id int -> ); Query OK, 0 rows affected (0.01 sec) #老邢带学生有哪些? select teacher.t_name, student.s_name from teacher, student where teacher.t_id = student.teacher_id and teacher.t_name = "老邢"; mysql> select teacher.t_name, student.s_name -> from teacher, student -> where teacher.t_id = student.teacher_id and teacher.t_name = "老邢"; +--------+--------+ | t_name | s_name | +--------+--------+ | 1 | 张三 | | 1 | 王五 | | 1 | 老八 | +--------+--------+ 4 rows in set (0.00 sec) mysql> select t.t_name,s.s_name -> from teacher t -> inner join student s -> on t.t_id = s.teacher_id -> where t.t_name = "老邢"; +--------+--------+ | t_name | s_name | +--------+--------+ |1 | 张三 | | 1 | 李四 | | 1 | 王五 | | 1 | 老八 | +--------+--------+ 4 rows in set (0.00 sec)
3.2多对多的场景
场景: 学生和课程的关系 学生要选课 课要被选 一个学生对应着多门的课程 一个课程可以被多个学生选择
mysql> create table stu ( -> s_id int primary key auto_increment, -> s_name varchar(32) -> ); Query OK, 0 rows affected (0.01 sec) mysql> create table course ( -> c_id int primary key auto_increment, -> c_name varchar(32) -> ); Query OK, 0 rows affected (0.01 sec) mysql> create table stu_course ( -> id int primary key auto_increment, -> s_id int, -> c_id int -> ); Query OK, 0 rows affected (0.08 sec) #有三张表就意味着着必须使用三表联查 #需求: 司马懿选了哪些课程 select stu.s_name, course.c_name from stu, stu_course, course where stu.s_id = stu_course.s_id and stu_course.c_id = course.c_id and stu.s_name = "司马懿"; mysql> select * -> from stu, stu_course, course -> where stu.s_id = stu_course.s_id and stu_course.c_id = course.c_id and stu.s_name = "司马懿"; mysql> select stu.s_name, course.c_name -> from stu, stu_course, course -> where stu.s_id = stu_course.s_id and stu_course.c_id = course.c_id and stu.s_name = "司马懿"; ) #内连接的写法 select s.s_name, c.c_name from stu s inner join stu_course sc on s.s_id = sc.s_id inner join course c on sc.c_id = c.c_id where s.s_name = "司马懿"; mysql> select s.s_name, c.c_name -> from stu s -> inner join stu_course sc -> on s.s_id = sc.s_id -> inner join course c -> on sc.c_id = c.c_id -> where s.s_name = "司马懿"; select c.c_name, s.s_name from course c inner join stu_course sc on c.c_id = sc.c_id inner join stu s on sc.s_id = s.s_id where c.c_name = "挖掘机"; mysql> select c.c_name, s.s_name -> from course c -> inner join stu_course sc -> on c.c_id = sc.c_id -> inner join stu s -> on sc.s_id = s.s_id -> where c.c_name = "挖掘机";