mysql> select distinct job from emp; // distinct关键字去除重复记录
+-----------+
| job |
+-----------+
| CLERK |
| SALESMAN |
| MANAGER |
| ANALYST |
| PRESIDENT |
+-----------+
mysql> select ename, distinct job from emp; // 语法错误
以上的sql语句是错误的。
记住:distinct只能出现在所有字段的最前面,distinct后面所有的字段联合起来去重。
mysql> select distinct deptno,job from emp; // deptno,job联合起来去重
+--------+-----------+
| deptno | job |
+--------+-----------+
| 20 | CLERK |
| 30 | SALESMAN |
| 20 | MANAGER |
| 30 | MANAGER |
| 10 | MANAGER |
| 20 | ANALYST |
| 10 | PRESIDENT |
| 30 | CLERK |
| 10 | CLERK |
+--------+-----------+
案例:统计岗位的数量?
mysql> select count(distinct job) from emp;
+---------------------+
| count(distinct job) |
+---------------------+
| 5 |
+---------------------+
统计每个部门岗位的数量?
mysql> select deptno,count(distinct job) from emp group by deptno;
+--------+---------------------+
| deptno | count(distinct job) |
+--------+---------------------+
| 10 | 3 |
| 20 | 3 |
| 30 | 3 |
+--------+---------------------+
统计每个部门每个岗位员工的数量?
mysql> select deptno,job,count(distinct ename) from emp group by deptno,job;
+--------+-----------+-----------------------+
| deptno | job | count(distinct ename) |
+--------+-----------+-----------------------+
| 10 | CLERK | 1 |
| 10 | MANAGER | 1 |
| 10 | PRESIDENT | 1 |
| 20 | ANALYST | 2 |
| 20 | CLERK | 2 |
| 20 | MANAGER | 1 |
| 30 | CLERK | 1 |
| 30 | MANAGER | 1 |
| 30 | SALESMAN | 4 |
+--------+-----------+-----------------------+
在实际开发过程中,大部分情况下不是从单表中查询数据,一般都是从多张表联合查询取出最终的结果。
在实际开发过程中,一般一个业务都会对应多张表,比如:学术和班级,起码两张表。
stuno stuname classno classname
-------------------------------------------------------------
1 zs 1 清华大学
2 ls 1 清华大学
...
学生和班级信息存储到一张表中,结果就像上面一样,数据会存在大量的重复,导致数据的冗余。
根据语法出现的年代来划分,包括:
SQL92(一些老的DBA可能还在使用这种语法。DBA:DataBase Administator,数据管理员)
SQL99(比较新的语法)
根据表的连接方式来划分,包括:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接(左连接)
右外连接(右链接)
全连接(很少使用)
案例:找出每一个员工的部门名称,要求显示员工名和部门名。
EMP表:
mysql> select ename,deptno from emp;
+--------+--------+
| ename | deptno |
+--------+--------+
| SMITH | 20 |
| ALLEN | 30 |
| WARD | 30 |
| JONES | 20 |
| MARTIN | 30 |
| BLAKE | 30 |
| CLARK | 10 |
| SCOTT | 20 |
| KING | 10 |
| TURNER | 30 |
| ADAMS | 20 |
| JAMES | 30 |
| FORD | 20 |
| MILLER | 10 |
+--------+--------+
DEPT表:
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
mysql> select ename,dname from emp,dept;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | ACCOUNTING |
| SMITH | RESEARCH |
| SMITH | SALES |
| SMITH | OPERATIONS |
| ALLEN | ACCOUNTING |
| ALLEN | RESEARCH |
| ALLEN | SALES |
| ALLEN | OPERATIONS |
......
一共56条记录
笛卡尔现象:当两张表进行连接查询的时候,没有任何条件进行限制,最终的结果查询条数是两张表记录条数的乘积。
关于表的别名:
select e.ename, d.dname from emp e,dept d;
表的别名有什么好处?
第一:执行效率高。(没有别名的话,找ename的时候会去emp dept两张表中都找,也可以避免两张表中有相同内容导致的错误)
第二:可读性好。
思考:避免了笛卡尔积现象,会减少记录的匹配次数吗?
不会,次数还是56次,底层不会改变。只不过显示的是有效记录。
案例:找出每一个员工的部门名称,要求显示员工名和部门名称
select
e.ename, d.dname
from
emp e, dept d
where
e.deptno = d.deptno; // SQL92,老语法,以后不用
+--------+------------+
| ename | dname |
+--------+------------+
| CLARK | ACCOUNTING |
| KING | ACCOUNTING |
| MILLER | ACCOUNTING |
| SMITH | RESEARCH |
| JONES | RESEARCH |
| SCOTT | RESEARCH |
| ADAMS | RESEARCH |
| FORD | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| MARTIN | SALES |
| BLAKE | SALES |
| TURNER | SALES |
| JAMES | SALES |
+--------+------------+
案例:查询每个员工的部门名称,要求显示员工名和部门名。
SQL92:(太老了,不用了)
select
e.ename, d.dname
from
emp e,dept d
where
e.deptno = d.deptno;
SQL99:(常用)
select
e.ename, d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno;
// inner可以省略的,带着inner目的是可读性好一些。
select
e.ename, d.dname
from
emp e
inner join
dept d
on
e.deptno = d.deptno;
语法:
...
A
join
B
on
连接条件
where
...
SQL99语法结构更加清晰一些:表的连接条件和后来的where数据过滤条件分离了。
案例:要求找出每个员工的工资等级,要求显示员工名、工资、工资等级。
EMP表:
mysql> select ename,sal from emp;
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
SALGRADE表:
mysql> select * from salgrade;
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
// inner可以省略
select
e.ename,e.sal,s.grade
from
emp e
inner join
salgrade s
on
e.sal between s.losal and hisal;
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ALLEN | 1600.00 | 3 |
| WARD | 1250.00 | 2 |
| JONES | 2975.00 | 4 |
| MARTIN | 1250.00 | 2 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| KING | 5000.00 | 5 |
| TURNER | 1500.00 | 3 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| FORD | 3000.00 | 4 |
| MILLER | 1300.00 | 2 |
+--------+---------+-------+
案例:找出每个员工的上级领导,要求显示员工名和对应的领导名。
mysql> select empno,ename,mgr from emp;
EMP a 员工表
+-------+--------+------+
| empno | ename | mgr |
+-------+--------+------+
| 7369 | SMITH | 7902 |
| 7499 | ALLEN | 7698 |
| 7521 | WARD | 7698 |
| 7566 | JONES | 7839 |
| 7654 | MARTIN | 7698 |
| 7698 | BLAKE | 7839 |
| 7782 | CLARK | 7839 |
| 7788 | SCOTT | 7566 |
| 7839 | KING | NULL |
| 7844 | TURNER | 7698 |
| 7876 | ADAMS | 7788 |
| 7900 | JAMES | 7698 |
| 7902 | FORD | 7566 |
| 7934 | MILLER | 7782 |
+-------+--------+------+
EMP b 领导表(领导也是员工,也在emp表内)
+-------+--------+------+
| empno | ename | mgr |
+-------+--------+------+
| 7369 | SMITH | 7902 |
| 7499 | ALLEN | 7698 |
| 7521 | WARD | 7698 |
| 7566 | JONES | 7839 |
| 7654 | MARTIN | 7698 |
| 7698 | BLAKE | 7839 |
| 7782 | CLARK | 7839 |
| 7788 | SCOTT | 7566 |
| 7839 | KING | NULL |
| 7844 | TURNER | 7698 |
| 7876 | ADAMS | 7788 |
| 7900 | JAMES | 7698 |
| 7902 | FORD | 7566 |
| 7934 | MILLER | 7782 |
+-------+--------+------+
员工的领导编号 = 领导的员工编号
select
a.ename as '员工名', b.ename as '领导名'
from
emp a
inner join
emp b
on
a.mgr = b.empno;
+--------+--------+
| 员工名 | 领导名 |
+--------+--------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+--------+--------+
一共13条记录,King是老板,没有上级领导。
什么是外连接?和内连接有什么区别?
内连接:
假设A和B表进行连接,使用内连接的话,凡是A表和B表能够匹配上的记录查询出来,这就是内连接。
AB两张表没有祝福主副之分,两张表都是平等的。
外连接:
假设A和B表进行外连接的话,AB两张表中有一张表是主表,另一张是副表,主要是查询主表中的数据,
捎带这查询副表。当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL与之匹配。
外连接的分类:
左外连接(左连接):表示左边的这张表是主表。
右外连接(右连接):表示右边的这张表是主表。
左连接有右连接的写法,右连接也有对应左连接的写法。
案例:找出每个员工的上级领导,要求显示员工名和对应的领导名。(所有员工必须全部查询出来)
内连接:
select
a.ename '员工', b.ename '领导'
from
emp a
join
emp b
on
a.mgr = b.empno;
外连接:(左外连接/左连接)outer可以省略
select
a.ename '员工', b.ename '领导'
from
emp a
left outer join
emp b
on
a.mgr = b.empno;
外连接:(右外连接/右连接)outer可以省略
select
a.ename '员工', b.ename '领导'
from
emp b
right outer join
emp a
on
a.mgr = b.empno;
+--------+-------+
| 员工 | 领导 |
+--------+-------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| KING | NULL |
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+--------+-------+
14 rows in set (0.00 sec)
外连接的最重要的特点:主表的数据无条件的全部查询出来。
案例:找出哪个部门没有员工?
EMP表:
+-------+--------+--------+
| empno | ename | deptno |
+-------+--------+--------+
| 7369 | SMITH | 20 |
| 7499 | ALLEN | 30 |
| 7521 | WARD | 30 |
| 7566 | JONES | 20 |
| 7654 | MARTIN | 30 |
| 7698 | BLAKE | 30 |
| 7782 | CLARK | 10 |
| 7788 | SCOTT | 20 |
| 7839 | KING | 10 |
| 7844 | TURNER | 30 |
| 7876 | ADAMS | 20 |
| 7900 | JAMES | 30 |
| 7902 | FORD | 20 |
| 7934 | MILLER | 10 |
+-------+--------+--------+
DEPT表:
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
select
d.*
from
emp e
right join
dept d
on
e.deptno = d.deptno
where
e.ename is null;
+--------+------------+--------+
| DEPTNO | DNAME | LOC |
+--------+------------+--------+
| 40 | OPERATIONS | BOSTON |
+--------+------------+--------+
案例:找出每个员工的部门名称以及工资等级。
EMP表:
+-------+--------+--------+---------+
| empno | ename | deptno | sal |
+-------+--------+--------+---------+
| 7369 | SMITH | 20 | 800.00 |
| 7499 | ALLEN | 30 | 1600.00 |
| 7521 | WARD | 30 | 1250.00 |
| 7566 | JONES | 20 | 2975.00 |
| 7654 | MARTIN | 30 | 1250.00 |
| 7698 | BLAKE | 30 | 2850.00 |
| 7782 | CLARK | 10 | 2450.00 |
| 7788 | SCOTT | 20 | 3000.00 |
| 7839 | KING | 10 | 5000.00 |
| 7844 | TURNER | 30 | 1500.00 |
| 7876 | ADAMS | 20 | 1100.00 |
| 7900 | JAMES | 30 | 950.00 |
| 7902 | FORD | 20 | 3000.00 |
| 7934 | MILLER | 10 | 1300.00 |
+-------+--------+--------+---------+
DEPT表:
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
SALGRADE表:
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
注意:
...
A
join
B
on
...
join
C
on
...
表示:A表和B表先进行连接,连接之后A表继续和C表进行连接。
select
e.ename,d.dname,s.grade
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal;
案例:找出每一个员工的部门名称、工资等级、上级领导
select
e.ename '员工',d.dname '部门名称',s.grade '工资等级',e1.ename '领导'
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal
left join
emp e1
on
e.mgr = e1.empno;
+--------+------------+----------+-------+
| 员工 | 部门名称 | 工资等级 | 领导 |
+--------+------------+----------+-------+
| SMITH | RESEARCH | 1 | FORD |
| ALLEN | SALES | 3 | BLAKE |
| WARD | SALES | 2 | BLAKE |
| JONES | RESEARCH | 4 | KING |
| MARTIN | SALES | 2 | BLAKE |
| BLAKE | SALES | 4 | KING |
| CLARK | ACCOUNTING | 4 | KING |
| SCOTT | RESEARCH | 4 | JONES |
| KING | ACCOUNTING | 5 | NULL |
| TURNER | SALES | 3 | BLAKE |
| ADAMS | RESEARCH | 1 | SCOTT |
| JAMES | SALES | 1 | BLAKE |
| FORD | RESEARCH | 4 | JONES |
| MILLER | ACCOUNTING | 2 | CLARK |
+--------+------------+----------+-------+
select语句中嵌套select语句,被嵌套的select语句是子查询。
子查询都可以出现在哪里?
select
..(select).
from
..(select).
where
..(select).
案例:找出高于平均薪资的员工信息
select ename,sal from emp where sal > avg(sal); //错误写法,where后面不能直接跟分组函数
mysql> select ename,sal from emp where sal >(select avg(sal) from emp);
+-------+---------+
| ename | sal |
+-------+---------+
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| FORD | 3000.00 |
+-------+---------+
案例:找出每个部门平均薪水的工资等级
select
t.* ,s.grade
from
(select deptno,avg(sal) as avgsal from emp group by deptno) t
join
salgrade s
on
t.avgsal between s.losal and hisal;
+--------+-------------+-------+
| deptno | avgsal | grade |
+--------+-------------+-------+
| 30 | 1566.666667 | 3 |
| 10 | 2916.666667 | 4 |
| 20 | 2175.000000 | 4 |
+--------+-------------+-------+
案例:找出每个部门平均的薪水等级
select
t.ed '部门编号', avg(t.sg) '平均薪资等级'
from
(select
e.ename,e.deptno as ed,s.grade as sg
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal) t
group by
t.ed;
+----------+--------------+
| 部门编号 | 平均薪资等级 |
+----------+--------------+
| 10 | 3.6667 |
| 20 | 2.8000 |
| 30 | 2.5000 |
+----------+--------------+
案例:找出每个员工所在的部门名称,要求显示员工名和部门名。
以前用连接写过:
select
e.ename, d.name
from
emp e
join
dept d
on
e.deptno = d.deptno;
如果用嵌套:
select
e.ename, (select d.dname from dept d where e.deptno = d.deptno) as dname
from
emp e;
案例:找出工作岗位是SALESMAN和MANAGER的员工?
第一种:select ename,job from emp where job='SALESMAN' or job='MANAGER';
第二种:select ename,job from emp where job in ('SALESMAN','MANAGER');
第三种:使用union
select ename,job from emp where job = 'MANAGER'
union
select ename,job from emp where job = 'SALESMAN';
+--------+----------+
| ename | job |
+--------+----------+
| JONES | MANAGER |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| MARTIN | SALESMAN |
| TURNER | SALESMAN |
+--------+----------+
两张不相干的表中数据拼接在一起显示?
select ename from emp
union
select dname from dept; // ename和dname行数不一致,合并在一列了
+------------+
| ename |
+------------+
| SMITH |
| ALLEN |
| WARD |
| JONES |
| MARTIN |
| BLAKE |
| CLARK |
| SCOTT |
| KING |
| TURNER |
| ADAMS |
| JAMES |
| FORD |
| MILLER |
| ACCOUNTING |
| RESEARCH |
| SALES |
| OPERATIONS |
+------------+
// 注意:当两个表列数不一致时会报错
mysql> select ename,sal from emp
-> union
-> select dname from dept;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
limit startIndex, length
startIndex表示起始位置,从0开始,0表示第一条数据
length表示取几个
startIndex可以省略不写,默认为0
案例:取出工资前5名的员工
select
ename,sal
from
emp
order by
sal desc
limit
0,5;
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
select
... 5
from
... 1
where
... 2
group by
... 3
having
... 4
order by
... 6
limit
...; 7
每页显示3条记录:
第1页:0,3
第2页:3,3
第3页:6,3
...
网站或者其他产品每页显示部分信息,这时就需要标准分页。