外键字段>>>:部门编号
其实就是用来标识表与表之间的数据关系
# 简单的理解为该字段可以让你去到其他表中查找数据
# 一对多、多对多、一对一、没有关系
### 一对多的表关系:
员工表:一个员工一个部门 x 部门表:一个部门有多个人 √
# 结论:一个可以,一个不可以,表关系就是:一对多
# 针对于一对多:外键字段要建在多的一方
在SQL层面建立一对多的关系: 先把基础表的中基础字段建立出来,然后在考虑外键字段
create table emp( # 员工表,关联 id int primary key auto_increment, name varchar(32), age int, dep_id int, foreign key(dep_id) references dep(id) # 让两张表建立了外键关系 on update cascade # 级联更新 on delete cascade # 级联删除 ); create table dep( # 部门表,被关联 id int primary key auto_increment, dep_name varchar(32), dep_desc varchar(32) );
insert into emp(name, age, dep_id) values('kevin', 20, 1); insert into dep(dep_name,dep_desc) values('人事部', '管理人才');
# 注意:1、在创建表时,要先创建被关联表(没有外键字段的表)2、在插入新数据时,要先确保被关联表的数据
3、在插入新数据时,外键字段只能填写被关联表中已有数据
4、只有添加了额外配置才能修改和删除被关联表的数据--级联更新、级联删除
一本书多个作者 一个作者可以写多本书
# 结论:如果两个都可以,那么表关系就是'多对多'
# 针对于多对多的表关系:外键字段建在第三张表中
在SQL层面建立多对多的表关系
create table book( id int primary key auto_increment, title varchar(32), price decimal(8,2) ); create table author( id int primary key auto_increment, name varchar(32), addr varchar(32) ); create table book2author( id int primary key auto_increment, book_id int, author_id int, foreign key(book_id) references author(id) # 让两张表建立了外键关系 on update cascade # 级联更新 on delete cascade, # 级联删除 foreign key(author_id) references book(id) # 让两张表建立了外键关系 on update cascade # 级联更新 on delete cascade ); ## 录入数据 insert into book(title, price) values('金瓶梅', 1000); insert into book(title, price) values('西游记', 2000); insert into author(name, addr) values('zhangsan', 'beijing'); insert into author(name, addr) values('lisi', 'shanghai'); insert into book2author(book_id, author_id) values(1, 1); insert into book2author(book_id, author_id) values(1, 2); insert into book2author(book_id, author_id) values(2, 1); insert into book2author(book_id, author_id) values(2, 2); ### 一对一: 作者表 作者详情表 /分为热数据和冷数据 # 针对一对一:两张表都可以,但是,推荐建在查询频率较高的一张表 在SQL层建立一对一的关系 create table author1( id int primary key auto_increment, name varchar(32), gender varchar(32), author_detail_id int unique, foreign key(author_detail_id) references author_detail(id) on update cascade on delete cascade ); create table author_detail( id int primary key auto_increment, qq varchar(32), email varchar(32) );
# 在此之前,都是单表下的查询
# 多表查询的思路是:
1. 子查询: 一条SQL的执行结果就是另外一条SQL的执行条件,其实就是分步操作
1\应该先查询kevin 的部门编号(部门表的id)
select dep_id from emp where name='kevin';
2\然后拿着查询出来的部门id去dep表中查询部门名称
select *from dep where id = (select dep_id from emp where name='kevin';);
2. 连表查询(重点): 把多张有关系的表链接成一张大的虚拟表,连接出来的虚拟表不是实际存 在的,它是在内存中存储,然后按照单表查询
# 如果两张表没有建立强制的约束关系,就使用逻辑上的关联 select * from emp,dep where emp.dep_id= dep.id
# 专业的连表语法:
inner join # 内连接,查询的是两张表中都有的数据
left join # 左连接,查询左表中所有的数据,右表没有的数据,使用NULL填充
right join # 右连接,查询右表中所有的数据,右表没有的数据,使用NULL填充
union # 连接两个SQL语句的结果select * from emp left join dep on emp.dep_id=dep.id union select * from emp right join dep on emp.dep_id=dep.id;
# 后面可以跟where条件,查后过滤
select * from emp left join dep on emp.dep_id=dep.id inner join A on A.id=dep.A_id where ...;
# 基本上是不用写SQL语句
Navicat的使用需要下载
'''它不是免费的,收费的,所以:1. 花钱去买,2. 白嫖,3. 免费试用14天'''
#1. Windows版本
#2. Mac版本去官网下载:https://www.navicat.com.cn/products/
连接mysql命令:mysql -h127.0.0.1 -P3306 -uroot -p123456
# 自己电脑
mysql -u root -p# 127.0.0.1---------一样的-------->localhost
1、查询所有的课程的名称以及对应的任课老师姓名
2、查询平均成绩大于八十分的同学的姓名和平均成绩
3、查询没有报李平老师课的学生姓名
4、查询挂科超过两门(包括两门)的学生姓名和班级
'''可能有点难,自己做,能做几个做几个.'''# 编写SQL不要想着一次性写完 可以边写边看
练习题SQL文件
数据导入: Navicat Premium Data Transfer Source Server : localhost Source Server Type : MySQL Source Server Version : 50624 Source Host : localhost Source Database : sqlexam Target Server Type : MySQL Target Server Version : 50624 File Encoding : utf-8 Date: 10/21/2016 06:46:46 AM */ SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `class` -- ---------------------------- DROP TABLE IF EXISTS `class`; CREATE TABLE `class` ( `cid` int(11) NOT NULL AUTO_INCREMENT, `caption` varchar(32) NOT NULL, PRIMARY KEY (`cid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `class` -- ---------------------------- BEGIN; INSERT INTO `class` VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班'); COMMIT; -- ---------------------------- -- Table structure for `course` -- ---------------------------- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `cid` int(11) NOT NULL AUTO_INCREMENT, `cname` varchar(32) NOT NULL, `teacher_id` int(11) NOT NULL, PRIMARY KEY (`cid`), KEY `fk_course_teacher` (`teacher_id`), CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `course` -- ---------------------------- BEGIN; INSERT INTO `course` VALUES ('1', '生物', '1'), ('2', '物理', '2'), ('3', '体育', '3'), ('4', '美术', '2'); COMMIT; -- ---------------------------- -- Table structure for `score` -- ---------------------------- DROP TABLE IF EXISTS `score`; CREATE TABLE `score` ( `sid` int(11) NOT NULL AUTO_INCREMENT, `student_id` int(11) NOT NULL, `course_id` int(11) NOT NULL, `num` int(11) NOT NULL, PRIMARY KEY (`sid`), KEY `fk_score_student` (`student_id`), KEY `fk_score_course` (`course_id`), CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`), CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`) ) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `score` -- ---------------------------- BEGIN; INSERT INTO `score` VALUES ('1', '1', '1', '10'), ('2', '1', '2', '9'), ('5', '1', '4', '66'), ('6', '2', '1', '8'), ('8', '2', '3', '68'), ('9', '2', '4', '99'), ('10', '3', '1', '77'), ('11', '3', '2', '66'), ('12', '3', '3', '87'), ('13', '3', '4', '99'), ('14', '4', '1', '79'), ('15', '4', '2', '11'), ('16', '4', '3', '67'), ('17', '4', '4', '100'), ('18', '5', '1', '79'), ('19', '5', '2', '11'), ('20', '5', '3', '67'), ('21', '5', '4', '100'), ('22', '6', '1', '9'), ('23', '6', '2', '100'), ('24', '6', '3', '67'), ('25', '6', '4', '100'), ('26', '7', '1', '9'), ('27', '7', '2', '100'), ('28', '7', '3', '67'), ('29', '7', '4', '88'), ('30', '8', '1', '9'), ('31', '8', '2', '100'), ('32', '8', '3', '67'), ('33', '8', '4', '88'), ('34', '9', '1', '91'), ('35', '9', '2', '88'), ('36', '9', '3', '67'), ('37', '9', '4', '22'), ('38', '10', '1', '90'), ('39', '10', '2', '77'), ('40', '10', '3', '43'), ('41', '10', '4', '87'), ('42', '11', '1', '90'), ('43', '11', '2', '77'), ('44', '11', '3', '43'), ('45', '11', '4', '87'), ('46', '12', '1', '90'), ('47', '12', '2', '77'), ('48', '12', '3', '43'), ('49', '12', '4', '87'), ('52', '13', '3', '87'); COMMIT; -- ---------------------------- -- Table structure for `student` -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `sid` int(11) NOT NULL AUTO_INCREMENT, `gender` char(1) NOT NULL, `class_id` int(11) NOT NULL, `sname` varchar(32) NOT NULL, PRIMARY KEY (`sid`), KEY `fk_class` (`class_id`), CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`) ) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `student` -- ---------------------------- BEGIN; INSERT INTO `student` VALUES ('1', '男', '1', '理解'), ('2', '女', '1', '钢蛋'), ('3', '男', '1', '张三'), ('4', '男', '1', '张一'), ('5', '女', '1', '张二'), ('6', '男', '1', '张四'), ('7', '女', '2', '铁锤'), ('8', '男', '2', '李三'), ('9', '男', '2', '李一'), ('10', '女', '2', '李二'), ('11', '男', '2', '李四'), ('12', '女', '3', '如花'), ('13', '男', '3', '刘三'), ('14', '男', '3', '刘一'), ('15', '女', '3', '刘二'), ('16', '男', '3', '刘四'); COMMIT; -- ---------------------------- -- Table structure for `teacher` -- ---------------------------- DROP TABLE IF EXISTS `teacher`; CREATE TABLE `teacher` ( `tid` int(11) NOT NULL AUTO_INCREMENT, `tname` varchar(32) NOT NULL, PRIMARY KEY (`tid`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `teacher` -- ---------------------------- BEGIN; INSERT INTO `teacher` VALUES ('1', '张磊老师'), ('2', '李平老师'), ('3', '刘海燕老师'), ('4', '朱云海老师'), ('5', '李杰老师'); COMMIT; SET FOREIGN_KEY_CHECKS = 1;
练习题答案
-- 1、查询所有的课程的名称以及对应的任课老师姓名 -- SELECT -- teacher.tname, -- course.cname -- FROM -- teacher -- INNER JOIN course ON teacher.tid = course.teacher_id; -- 2、查询平均成绩大于八十分的同学的姓名和平均成绩 # 1.先确定需要使用到的表 # 2.在思考多表查询的方式 # 第一步先查询成绩表中 平均成绩大于80的学生编号 # 1.1 按照学生id分组并获取平均成绩 -- select student_id,avg(num) from score group by student_id; # 1.2 筛选出平均成绩大于80的数据 (针对聚合函数的字段结果 最好起别名防止冲突) -- select student_id,avg(num) as avg_num from score group by student_id having avg(num) > 80; # 1.3 将上述SQL的结果与student表拼接 -- SELECT -- student.sname, -- t1.avg_num -- FROM -- student -- INNER JOIN ( SELECT student_id, avg( num ) AS avg_num FROM score GROUP BY student_id HAVING avg( num ) > 80 ) AS t1 ON student.sid = t1.student_id; -- 3、查询没有报李平老师课的学生姓名 # 1.先查询李平老师教授的课程编号 -- select course.cid from course where teacher_id = -- (select tid from teacher where tname ='李平老师'); # 2.根据课程id号筛选出所有报了的学生id号 -- select distinct score.student_id from score where course_id in (select course.cid from course where teacher_id = -- (select tid from teacher where tname ='李平老师')); # 3.去学生表中根据id号取反筛选学生姓名 -- SELECT -- student.sname -- FROM -- student -- WHERE -- sid NOT IN ( -- SELECT DISTINCT -- score.student_id -- FROM -- score -- WHERE -- course_id IN ( SELECT course.cid FROM course WHERE teacher_id = ( SELECT tid FROM teacher WHERE tname = '李平老师' ) ) -- ); -- 4、查询挂科超过两门(包括两门)的学生姓名和班级 # 1.先筛选出小于60分的数据 -- select * from score where num < 60; # 2.按照学生id分组 然后统计挂科数量 -- select student_id,count(course_id) from score where num < 60 group by student_id; # 3.筛选出挂科超过两门的学生id -- select student_id from score where num < 60 group by student_id -- having count(course_id) >=2; # 4.先将上述结果放在一边 去连接student和class表 SELECT student.sname, class.caption FROM class INNER JOIN student ON class.cid = student.class_id WHERE student.sid IN ( SELECT student_id FROM score WHERE num < 60 GROUP BY student_id HAVING count( course_id ) >= 2 );