一. 关联查询的基础、高级关联查询、约束
1.分组查询:
当统计一张表或者按照表内的某字段进行分组的总记录数,or最大值,最小值,平均值,总和等
一定会与分组函数连用:count(),min(),max(),avg(),avg(ifnull(comm,0))
2.概念:
当在查询时,我们所需要的数据不在一张表中,可能在两张表或多张表中。此时我们需要同时操作这些表。即关联查询。
3.等值连接:
在做多张表查询时,这些表中应该存在着有关联的两个字段。
我们使用某一张表中的一条记录与另外一张表通过相关联的两个字段进行匹配,组合成一条记录。
4.笛卡儿积:
在做多张表查询时,我们使用某一张表中的每一条记录都与
另外一张表的所有记录进行组合。比如表A有x条,表B有y条件,最终组合数为x*y,这个值就是笛卡尔积,通常没有意义。
5.内链接:
只要使用join on,就是内连接。连接效果与等值连接一样。
用法:
表A join 表2 on 关联条件
6.外连接:
在做多张表查询的时候,我们所需的数据,除了满足关联条件的数据外,还有不满足管理条件的数据。此时需要使用外连接。会涉及到两个概念:
驱动表(主表):除了显示满足条件的数据,还需要显示不满足条件的 数据的表
从表:只显示满足关联条件的数据的表
外连接分三种情况:
- 左外连接:表A left [outer] join 表B on 关联条件
表A时驱动表,表B是从表
- 右外连接:表A right [outer] join 表B on 关联条件
表B时驱动表,表A是从表
- 全外连接:两张表的数据不管满不满足条件,都做显示。
表A full [outer] join 表B on 关联条件
Ps:mysql 不支持全外连接
- 自连接:在多张表进行关联查询时,这些表的表名相同。即,自连接。
- 高级关联查询:
有的时候,我们要查询的数据, 一个简单的查询语句满足不了,并且我们使用的数据,表中不能直观体现出来。而是预先经过一次查询才会有所体现。那么先执行的查询,我们称之子查询。被子查询嵌入的查询语句称之为父查询。
比如需求:查询工资大于员工JONES工资的员工的信息。
子查询返回的数据特点:
(1) 可能是单行单列的数据。
(2) 可能是多行单列的数据
(3) 可能是单行多列的数据
(4) 可能是多行多列的数据
1)子查询可以在where子句中
2)子查询可以在from子句中
3)子查询可以在having子句中
4)子查询可以在select字句中,相当于外连接的另外一种写法。
7.约束Constraint:对插入表中的数据起到一定的条件限制.
约束有五种:
主键约束:primary key 要求作为主键的字段值 非空且唯一
非空约束:not null
唯一性约束:unique (null与null不相等)
检查性约束:gender enum(’f’,’m’) 其他数据库:check(条件) check(gender in(’f’, ’m’))
外键约束:foreign key
要求:有外键约束的字段A必须依赖于另外一个字段,字段B要有主键约束。字段A的值是null,要么必须是字段B里的值。
序列:作为主键的字段,通常不是表中的主要信息,可以用来当成信息记录的序号。序号最好是有序的序列。
Auto_increment 关键字,用来对主键约束的字段做自增操作。
用法:
create table t_05(
empno int primary key,
ename varchar(20) not null,
idcard varchar(18) unique,
gender enum('f','m'),
mgr int ,
foreign key(mgr) references t_05(empno)
);
函数:last_insert_id()
作用:获取序列最后一次的值
二.练习题
1:查看10号部门,职位为MANAGER的员工信息
select * from emp where deptno=10 and job='manager';
2:查看工资不小于1500,不大于3000的所有员工信息
select * from emp where sal between 1500 and 3000;
3:查看不是10号和20号部门的所有员工信息
select * from emp where deptno not in (10,20) or deptno is null;
4:查询集合(12,10,1,5,6)中的最大值和最小值
select greatest(12,10,1,5,6),least(12,10,1,5,6);
5:查看10,20,30号部门中姓名中有A的员工的员工编号
select deptno,ename,empno from emp where ename like '%a%'
and deptno in(10,20,30);
6:查看10,20号每个部门的最高月薪,平均奖金,部门人数
select max((sal)+ifnull(comm,0)),avg(ifnull(comm,0)),count(*) from emp
where deptno in(10,20) group by deptno;
7:查看部门平均工资大于1000的所有部门号,平均奖金,按照部门号降序排序。
select deptno,avg(ifnull(comm,0)) from emp group by deptno having
avg(ifnull(sal,0))>1000 order by deptno desc;
8:查询领导编号
select distinct mgr from emp where mgr is not null;
【关联查询基础】
1、等值连接
练习1:查询部门表的名称及其每个部门的员工的员工编号和姓名及其职位,部门号。
按照部门号降序排序。
select dept.deptno, dname, empno,ename,job from emp,dept
where emp.deptno=dept.deptno
order by emp.deptno desc;
内连接:使用join on 进行等值连接
格式:表A join 表B on 关联条件
练习2:使用内连接修改练习1
select dept.deptno,dname,empno,ename,job from emp join dept
on emp.deptno=dept.deptno
order by emp.deptno desc;
练习3:查询20和30部门的部门名称,部门地址及其员工的姓名和工资。
select d.deptno 'dno',d.dname,d.loc,e.ename,e.sal from emp e join dept d on
e.deptno = d.deptno
where e.deptno in (20,30)
order by dno ;
外连接: 驱动表,从表
左外连接: 表A left join 表B on 关联条件
练习1:查询员工表的所有信息及其员工所在部门的信息。
select e.*,d.* from emp e left join dept d on e.deptno=d.deptno;
右外连接: 表A right join 表B on 关联条件
练习2:使用右外连接查询部门表的所有信息及其员工信息。
select d.*,e.* from emp e right join dept d on e.deptno=d.deptno;
自连接:
练习1:查询员工的 编号,姓名及其领导编号和姓名。
select e1.empno "员工编号",e1.ename "员工姓名",e2.empno "领导编号",
e2.ename "领导姓名"
from emp e1 join emp e2 on e1.mgr = e2.empno;
练习2:查询领导的姓名及其下属的姓名。
select m.ename "领导姓名",e.ename "员工姓名" from emp e join emp m on e.mgr = m.empno;
【高级关联查询】
子查询,父查询
1、子查询在where子句中
练习1:查询工资大于员工JONES工资的员工的信息
第一步:select sal from emp where ename='jones';
第二步:select * from emp where sal>(xxx);
合并:
select * from emp where sal>(select sal from emp where ename='jones');
练习2:查询员工表中工资大于10号部门的平均工资的
员工的姓名,职位,工资及其部门号
第一步:select avg(ifnull(sal,0)) from emp where deptno=10;
第二步:
select ename,job,sal,deptno from emp where sal>
(select avg(ifnull(sal,0)) from emp where deptno=10);
练习3:查询工资等于每个部门的平均工资的人员信息
select avg(ifnull(sal,0)) from emp group by deptno;
select * from emp where sal in (select avg(ifnull(sal,0)) from emp group by deptno);
练习4:查询工资大于所有部门的平均工资的人员信息
select * from emp where sal >all(select avg(ifnull(sal,0)) from emp group by deptno);
练习5:查询工资大于任意部门的平均工资的人员信息
select * from emp where sal >any(select avg(ifnull(sal,0)) from emp group by deptno);
练习6:现将clark和scott的奖金修改成300
SET SQL_SAFE_UPDATES = 0; 解锁(解开只能根据主键增删改查的mysql权限)
查询工资和奖金与员工scott相同的其他员工信息
select * from emp where sal=(select sal from emp where ename='scott')
and comm = (select comm from emp where ename='scott') and ename<>'scott';
select * from emp where (sal,ifnull(comm,0))=(select sal,ifnull(comm,0) from emp where ename='scoot')
and ename<>'scott';
子查询在from子句中
练习1:查询每个员工的工资,姓名和其部门的平均工资。
分步思考:emp表中有 工资和姓名的字段
而要显示的平均工资,这个字段不存在。
其他表中如果有平均工资字段就好了。这两张表就可以做关联查询。关联条件
应该是两张表中的部门字段。
第一步:查询每个部门的平均工资
select deptno,avg(ifnull(sal,0)) 'avg' from emp group by deptno;
第二步:做关联查询(将上一步的查询语句看成一张表)
select sal,ename,avg_sal from emp join (select deptno,avg(ifnull(sal,0)) 'avg_sal' from emp group by deptno) t
on emp.deptno = t.deptno order by t.deptno;
练习2:查询大于本部门平均工资的员工的信息。
select sal,ename,avg_sal from emp join (select deptno,avg(ifnull(sal,0)) 'avg_sal' from emp group by deptno) t
on emp.deptno = t.deptno and emp.sal>t.avg_sal order by t.deptno;
子查询在having子句中
练习1:查询部门平均工资大于30部门平均工资的部门平均工资,工资之和,
最大工资,最小工资,总人数。
select deptno,avg(ifnull(sal,0)),sum(sal),max(sal),min(sal),count(*)
from emp group by deptno having avg(ifnull(sal,0))>
(select avg(ifnull(sal,0)) from emp where deptno=30);
子查询在select子句中。
练习1:查询每个员工的姓名,工资,及其部门的平均工资,工资之和。
select ename,sal,
(select avg(ifnull(sal,0)) from emp a where a.deptno=b.deptno) avg_sal ,
(select sum(sal) from emp c where c.deptno=b.deptno ) sum_sal
from emp b order by b.deptno;
约束:
主键约束
练习1:创建表t_01 字段tid int 设置为主键约束,tname varchar(20).
create table t_01(
tid int primary key,
tname varchar(20)
);
插入数据: 1001,‘zhangsan’
1002, ‘李四’
insert into t_01 values(1001,'zhangsan');
insert into t_01 values(1002,'lisi');
insert into t_01 values(null,'wangwu');
非空约束:
create table t_02(
tid int primary key,
tname varchar(20) not null
);
insert into t_02 values(1001,'zhangsan');
insert into t_02 values(1002,null);
唯一性约束
create table t_03(
tid int primary key,
tname varchar(20) not null,
idcard varchar(18) unique
);
insert into t_03 values(1001,'zhangsan',null);
insert into t_03 values(1002,'zhangsan','123456789');
insert into t_03 values(1003,'zhangsan','223456789');
检查性约束
create table t_04(
tid int primary key,
tname varchar(20) not null,
idcard varchar(18) unique,
gender enum('f','m')
);
insert into t_04 values (1001,'zhangsan','123456789','f');
insert into t_04 values (1002,'zhangsan','223456789','m');
insert into t_04 values (1003,'zhangsan','323456789','a');
外键约束:
create table t_05(
empno int primary key,
ename varchar(20) not null,
idcard varchar(18) unique,
gender enum('f','m'),
mgr int ,
foreign key(mgr) references t_05(empno)
);
insert into t_05 values (1001,'zs','123456789','m',null);
insert into t_05 values (1002,'ls','223456789','m',1001);
序列:
create table t_06(
tid int primary key auto_increment,
tname varchar(20) not null
);
insert into t_06 values(1001,'zs');
insert into t_06 values(null,'ls');
insert into t_06 (tname) values('ww');
insert into t_06 values(last_insert_id()+1,'zl');