关联查询
一、分组与限制
分组过滤
语法:select 字段 from 表 where 条件 group by 字段 having 条件
分组过滤having和where类似,都是用于条件判断;
区别在于:where是最核心的条件判断; 但having智能用在分组和的条件判断
#分组过滤:
#统计60、70、90号部门的最高工资
#思路:
#1). 确定分组依据(department_id)
select department_id from t_employees group by department_id;
#2). 对分组后的数据,过滤出部门编号是60、70、90信息
select department_id from t_employees group by department_id having department_id in(60,70,90);
#3). max()函数处理
select department_id,max(salary) from t_employees group by department_id having department_id in(60,70,90);
结果限制
#限定查询 限定查询出来的条数 SELECT 列名 FROM 表名 [LIMIT 起始行,查询行数]()
#应用场景:分页查询
#查询表中前五名员工的所有信息
select * from t_employees limit 0,5;
#查询表中从第四条开始,查询 10 行
select * from t_employees limit 3,10;
#分页: 每页5条 第1页:0,5 第2页:5,5 第3页:10,5
#算法: 起始行=(当前页-1)*每页条数
编写顺序
select 字段 from 表 where 条件 group by 字段 having 条件 order by 字段 limit 起始行,条数
二、子查询
概述:会出现两个查询语句;一个查询的结果,是另一个查询的条件;这个结果就是子查询
单行单列
子查询的结果为单行单例;是最基本,也是最常用的一种子查询
#子查询--单行单列
#查询工资大于Bruce 的员工信息
#1.先查询到 Bruce 的工资(一行一列)
select salary from t_employees where FIRST_NAME='Bruce'; #子查询
#2.查询工资大于 Bruce 的员工信息
select * from t_employees where salary>6000;
#3.组合
select * from t_employees where salary>(select salary from t_employees where FIRST_NAME='Bruce');
多行单列
子查询的结果是多行单列的应用,往往有两种情况:1.枚举查询 2. all| any关键字
#枚举的多行单列: where 字段 in(值1,值2..)
#查询与名为'King'同一部门的员工信息
#思路:
#1. 先查询 'King' 所在的部门编号(多行单列)
select department_id from t_employees where LAST_NAME='King';
#2. 再查询80、90号部门的员工信息
select * from t_employees where department_id in(80,90);
#3.组合
select * from t_employees where department_id in(select department_id from t_employees where LAST_NAME='King');
#any|all的使用 any-匹配部分 all-匹配所有
#工资高于60部门所有人的信息
#1.查询 60 部门所有人的工资(多行单列)
select salary from t_employees where DEPARTMENT_ID=60;
#2.查询高于 60 部门所有人的工资的员工信息(高于所有-高于最高的)
select * from t_employees where salary > ALL(select salary from t_employees where DEPARTMENT_ID=60);
#。查询高于 60 部门的工资的员工信息(高于部分-高于最低的)
select * from t_employees where salary > ANY(select salary from t_employees where DEPARTMENT_ID=60);
多行多列
子查询的结果是一张虚拟表,继续当成表来使用即可
SELECT 列名 FROM(子查询的结果集)WHERE 条件;
#多行多列的子查询
#查询员工表中工资排名前 5 名的员工信息
#思路:
#1. 先对所有员工的薪资进行排序(排序后的临时表)
select * from t_employees order by salary desc;
#2. 再查询临时表中前5行员工信息
select * from (select * from t_employees order by salary desc) temp limit 0,5;
#简化写法:
select * from t_employees order by salary desc limit 0,5;
三、关联查询
合并查询
合并查询,需要合并多张表;在平时应用中不常用;合并的表字段数量要一致,否则会有问题
应用场景:多张表结构一致,并进行汇总才用到; 例如:多个班级学生信息汇总
#创建t1表和t2表
#合并查询
#合并两张表的结果,去除重复记录
select * from t1 UNION select * from t2;
#合并两张表的结果,不去除重复记录(显示所有)
select * from t1 UNION ALL select * from t2;
表连接查询
表连接查询分为:内连接和外连接
内连接:两张表中能够匹配上的记录则显示出来;匹配不上的,则不显示
外连接分为左外和右外:
左外:以左表为标准,所有记录都会显示;如果右表记录匹配不上则显示为null
右外:以右表为标准,所有记录都会显示;如果左表记录匹配不上则显示为null
#创建teacher表和couse表
#内连接:
select * from teacher t,couse c where t.id=c.t_id; #MySQL专用
select * from teacher t INNER JOIN couse c ON t.id=c.t_id; #统一标准
#左外连接
select * from teacher t LEFT JOIN couse c ON t.id=c.t_id;
#右外连接
select * from teacher t right JOIN couse c ON t.id=c.t_id;
#三表关联案例:
#查询所有员工工号、名字、部门名称、部门所在国家ID
#员工工号、名字-员工表; 部门名称-部门表 国家ID-地区表
select e.employee_id,e.first_name,d.DEPARTMENT_NAME,l.COUNTRY_ID from t_employees e
INNER JOIN t_departments d ON e.DEPARTMENT_ID=d.DEPARTMENT_ID
INNER JOIN t_locations l ON d.LOCATION_ID=l.LOCATION_ID;
四、DML操作
DML是数据操作语言,针对表中的增删改的操作; 查询则叫做DQL
添加
语法1:insert into 表名(字段1,字段2..) values(值1,值2…) —常用
语法2:insert into 表名 values(值1,值2…) 必须和表字段一一对应,且全部字段要添加数据
#添加一条工作岗位信息
insert into t_jobs(job_id,job_title,min_salary,max_salary) values('AD_IT','IT_PRO',10000,20000); #推荐
insert into t_jobs values('AD_XS','XSY',5000,15000); #注意:字段必须按顺序,且写全
修改
语法: update 表名 set 字段=值,字段2=值2 where 条件
注意:如果没有写where则匹配所有记录都进行了修改
#修改编号为100 的员工的工资为 25000
update t_employees set salary=25000 where EMPLOYEE_ID=100;
#修改编号为135 的员工信息岗位编号为 ST_MAN,工资为3500
update t_employees set JOB_ID='ST_MAN',salary=3500 where EMPLOYEE_ID=135;
删除
语法: delete from 表 where 条件
注意:必须要加where,否则删除表的所有记录
#删除编号为135 的员工
delete from t_employees where employee_id=135;
#删除姓Peter,并且名为 Hall 的员工
delete from t_employees where first_name='Peter' and last_name='Hall';
#清除数据表
TRUNCATE table teacher; #类似delete from teacher 区别:TRUNCATE 删除表再重新创建
五、数据表操作
数据类型
建表前,需要先弄清除数据库的数据类型分类,可以分为:数值类型,日期类型,字符串类型
这些类型重点记住:int,double(M,D), date,datetime,varchar(长度)
创建表
#创建表
create table sub(
id int,
name varchar(30),
hour int
)
insert into sub(id,name,hour) values(1,'java',60);
insert into sub(id,name,hour) values(2,'h5',55);
select * from sub;
数据表操作
#表字段的操作: ALTER TABLE 表名 操作;
#在课程表基础上添加gradeId 列
alter table sub add gradeId int;
#修改课程表中课程名称长度为10个字符
alter table sub MODIFY name varchar(10);
#删除课程表中 gradeId 列
alter table sub drop gradeId;
#修改课程表中 hour 列为 h
alter table sub change hour h int;
#修改课程表的sub 为 subs
alter table sub rename subs;
#删除subs表
drop table subs;
六、约束
问题:在往已创建表中新增数据时,可不可以新增两行相同列值得数据?]()
如果可行,会有什么弊端?
答:可以创建;弊端:无法识别唯一的一条记录; 造成数据的读写肯定会出问题; 需要进行约束
实体完整性约束
一条记录代表着一个实体对象,也是就每条记录都需要唯一性约束
主键约束
表中每条记录的唯一标识,不代表业务逻辑; 注意:主键不能为null
唯一约束
主键约束就是唯一约束,区别在于唯一约束设置到除id以外的字段;且允许为null
主键自增长
主键自增长,默认从1开始,每次添加都+1;添加数据更方便
#主键约束:
create table sub(
id int primary key auto_increment, #主键约束,不能为null 自增长
name varchar(20) UNIQUE, #唯一约束
hour int
)
select * from sub;
insert into sub(name,hour) values('java',60);
insert into sub(name,hour) values('h5',55);
域完整性约束
域完整性约束是针对字段中的单元格的值的范围的限制
create table sub(
id int primary key auto_increment,
name varchar(20) UNIQUE not null, #非空约束
hour int default 30 #默认值为30
)
select * from sub;
insert into sub(name) values('java');
insert into sub(name,hour) values('h5',55);
外键约束
两张表中的单元格的值的范围限制; 这两张表一张作为主表,一张作为从表
主表:关联字段的主键所在表为主表;关联字段的非主键所在表则是从表
外键约束规则:(注意:外键约束需要设置到从表中)
创建时,先创建主表;添加数据时,先添加主表数据
删除时,先删除从表或数据;再删除主表或数据
#外键约束
drop table teacher; #主表
drop table course; #从表
#先创建主表 创建时先创建主表及添加数据
create table teacher(
id int primary key auto_increment,
name varchar(20)
);
insert into teacher(name) values('凤姐');
insert into teacher(name) values('芙蓉');
select * from teacher;
#再创建从表,并设置外键约束
create table course(
id int primary key auto_increment,
name varchar(30),
t_id int, #外键 从表中的关联字段是外键
#CONSTRAINT 标记名 FOREIGN KEY(外键名) REFERENCES 主表(主键)
CONSTRAINT fk FOREIGN KEY(t_id) REFERENCES teacher(id) #外键约束
);
select * from course;
insert into course(name,t_id) values('h5',1); #添加时t_id只能时主键中存在的1或2的主键值
#删除时,先删从表或数据,再删主表或数据
七、事务
概述
事务是原子性操作(不可分割的整体);处在事务中的多个SQL语句,要么都成功,则提交;要么都失败,则回滚
事务的边界
事务的边界,就是事务开启或结束的过程
开始: 启动事务 start transaction; 开启事务后,则进入事务中;中间可执行SQL语句
执行多条SQL语句
结束:(提交或回滚)
提交:多条SQL语句都执行成功,则提交; commit;
回滚:如果有任意SQL语句失败,则回滚,回滚到未发生的状态; rollback;
原理
开启事务后,相当于开辟了缓冲区(回滚段);所有SQL指令的执行都是在缓冲区中进行;如果都成功了,则执行提交,意味着提交到数据库中永久写入;如果有失败的,则执行回滚(清除缓冲区)
事务特性
事务特性:ACID; 原子性,一致性,隔离性,持久性
原子性:事务操作要么都成功,要么都失败
一致性:事务的成功或失败,最终完成的状态是一致的(例如,转账的总和不变)
隔离性:处在事务中,与外界的操作是完全隔离的;除非进行了提交或回滚
持久性:进行了提交,则永久性写到了数据库中
应用
#事务的操作 ---模拟转账功能
#zs和ls都有1000块;zs转200给ls
create table account(
id int primary key auto_increment,
name varchar(20),
money int
)
insert into account(name,money) values('zs',1000);
insert into account(name,money) values('ls',1000);
select * from account;
start TRANSACTION; #开启事务
update account set money=money-200 where name='zs';
#中途出现异常,则会跳到回滚语句
update account set money=money+200 where name='ls';
commit; #上述的SQL操作无异常,则进入提交
rollback; #如果有一条语句出现异常,则会跳到回滚
八、总结与作业
总结
作业
#作业1
#1 查询2张表的数据,使用内连接和左外连接
#2 查询部门101和105部门所有员工工资,并按照降序排列
#3 查询部门101和105所有员工工资,并且按照工资降序排列,如果部门中工资相同,则按照性别排列(女在前)
#4 查询部门名称为主公的所有员工信息
#5 查询102部门的所有员工人数
#6 查询105部门的平均工资
#7 查询103部门中工资最高的和最低的
#8 查询每一个部门的工资总和并按照降序排列
#9 查询每一个部门的工资总和,要求只显示总工资大于90w的部门信息
#作业2
#1、 查询Student表中的所有记录的Sname、Ssex和Class列。
#2、 查询教师所有的单位即不重复的Depart列。
#3、 查询Student表的所有记录。
#4、 查询Score表中成绩在60到80之间的所有记录。
#5、 查询Score表中成绩为85,86或88的记录。
#6、 查询Student表中“95031”班或性别为“女”的同学记录。
#7、 以Class降序查询Student表的所有记录。
#8、 以Cno升序、Degree降序查询Score表的所有记录。
#9、 查询“95031”班的学生人数。
晨考
晨考:
student表
id ,uname,sex ,birth ,department ,address
(901,'张老大', '男',1985,'计算机系', '北京市海淀区'),
(902,'张老二', '男',1986,'中文系', '北京市昌平区'),
(903,'张三', '女',1990,'中文系', '湖南省永州市'),
(904,'李四', '男',1990,'英语系', '辽宁省阜新市'),
(905,'王五', '女',1991,'英语系', '福建省厦门市'),
(906,'王六', '男',1988,'计算机系', '湖南省衡阳市');
score表
stu_id ,c_name ,grade
(901, '计算机',98),
(901, '英语', 80),
(902, '计算机',65),
(902, '中文',88),
(903, '中文',95),
(904, '计算机',70),
(904, '英语',92),
(905, '英语',94),
(906, '计算机',90),
(906, '英语',85);
#1. 两张表根据学生ID进行内连接
#2. 分数降序排列,且只显示第2到第4名成绩信息
#1
select * from student s inner join score sc on s.id=sc.stu.id;
#2
select * from score order by grade desc limit 1,3;