您现在的位置是:首页 >技术杂谈 >mysql从零开始(2)网站首页技术杂谈
mysql从零开始(2)
接上文mysql从零开始(1)
12、把查询结果去除重复记录distinct
select distinct 字段名1, 字段名2 from 表名;
distinct 只能在所有字段的最前方,在最前方时表示将后面所有字段联合起来去重。比如,
mysql> select distinct job,deptno from emp;
+-----------+--------+
| job | deptno |
+-----------+--------+
| CLERK | 20 |
| SALESMAN | 30 |
| MANAGER | 20 |
| MANAGER | 30 |
| MANAGER | 10 |
| ANALYST | 20 |
| PRESIDENT | 10 |
| CLERK | 30 |
| CLERK | 10 |
+-----------+--------+
连接查询
从一张表中单独查询,即单表查询。多张表联合起来查询数据,称为连接查询。
当对两张表进行连接查询,并且没有添加任何条件时,最终查询结果的条数,是两张表的条数的乘机,这种现象被称为笛卡尔积现象,比如:
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 |
+--------+--------+
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
两张表连接没有任何条件限制:
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 rows in set (0.00 sec)
14 * 4 = 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 |
+--------+------------+
当然,尽管查询结果变少了,在匹配的过程中并没有减少,依然是56次匹配。
通过笛卡尔积现象可以得出,表的链接次数越多效率越低,我们应当尽量减少连接次数。
连接查询有以下几种:
- 内连接:两张表之间没有主次关系
- 等值连接
- 非等值连接
- 自连接
- 外连接:有主次关系
- 左连接
- 右连接
- 全连接
等值连接
连接条件是一个等量关系
select
别名1.字段名11, 别名2.字段名21
from
表名1 别名1
inner join
表名2 别名2
on
别名1.字段名12 = 别名2.字段名22
where
筛选条件
- inner可以省略,但是带着可读性好
- 使用join on比把链接条件和筛选条件全部放在where后面结构更清晰
非等值连接
连接条件是非等值,比如
显示员工姓名、工资、工资等级
select
e.ename, e.sal, s.grade
from
emp e
inner join
salgrade s
on
e.sal between s.losal and s.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 |
+--------+---------+-------+
自连接
即某张表的连接对象也是自己,比如
select
a.ename as '员工名', b.ename as '领导名'
from
emp a
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 |
+--------+--------+
外连接
外连接分为左外连接和右外连接,下面为右外连接:
select
别名1.字段名11, 别名2.字段名21
from
表名1 别名1
right outer join
表名2 别名2
on
别名1.字段名12 = 别名2.字段名22
where
筛选条件
right表示将join关键字右边的这张表看成主表,主要是为了将这张表的数据全部查询出来,次表的数据只是顺带显示。
在外连接中,任何一个左连接都有右连接的写法,任何一个右连接都有左连接的写法。比如:
select
e.ename,d.dname
from
emp e
right outer join
dept d
on
e.deptno = d.deptno;
select
e.ename,d.dname
from
dept d
left join
emp e
on
e.deptno = d.deptno;
在内连接中,将完成能够匹配上这个条件的数据查询出来。
select
e.ename,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno;
+--------+------------+
| 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 |
+--------+------------+
但是,在左连接中,一切以主表为准:
select
e.ename,d.dname
from
dept d
left outer join
emp e
on
e.deptno = d.deptno;
+--------+------------+
| 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 |
| NULL | OPERATIONS |
+--------+------------+
多表连接
select
...
from
a
join
b
on
a和b的连接条件
join
c
on
a和c的连接条件
right join
d
on
a和d的连接条件
案例:找出每个员工的部门名称以及工资等级,还有上级领导,
要求显示员工名、领导名、部门名、薪资、薪资等级
select
e.ename,e.sal,d.dname,s.grade,l.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 l
on
e.mgr = l.empno;
+--------+---------+------------+-------+-------+
| ename | sal | dname | grade | ename |
+--------+---------+------------+-------+-------+
| SMITH | 800.00 | RESEARCH | 1 | FORD |
| ALLEN | 1600.00 | SALES | 3 | BLAKE |
| WARD | 1250.00 | SALES | 2 | BLAKE |
| JONES | 2975.00 | RESEARCH | 4 | KING |
| MARTIN | 1250.00 | SALES | 2 | BLAKE |
| BLAKE | 2850.00 | SALES | 4 | KING |
| CLARK | 2450.00 | ACCOUNTING | 4 | KING |
| SCOTT | 3000.00 | RESEARCH | 4 | JONES |
| KING | 5000.00 | ACCOUNTING | 5 | NULL |
| TURNER | 1500.00 | SALES | 3 | BLAKE |
| ADAMS | 1100.00 | RESEARCH | 1 | SCOTT |
| JAMES | 950.00 | SALES | 1 | BLAKE |
| FORD | 3000.00 | RESEARCH | 4 | JONES |
| MILLER | 1300.00 | ACCOUNTING | 2 | CLARK |
+--------+---------+------------+-------+-------+
子查询
子查询的意思就是,在select语句里面嵌套select语句,被嵌套的select语句称为子查询。
将子查询的子表看成一张临时表。
where语句中的子查询
查询比最低工资高的员工姓名和工资。
此时不能直接使用
select
ename,sal
from
emp
where
sal > min(sal);
ERROR 1111 (HY000): Invalid use of group function
因为min函数是分组函数,不能直接用在where语句中。如果要用在where后可以使用子查询。
# 第一步
mysql>select min(sal) from emp;
+----------+
| min(sal) |
+----------+
| 800.00 |
+----------+
# 第二步
mysql>select ename,sal from emp where sal > (select min(sal) from emp);
+--------+---------+
| ename | sal |
+--------+---------+
| 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 |
+--------+---------+
from中的子查询
找出每个岗位的平均工资的薪资等级。
# 第一步,先想临时表如何构建
select job,avg(sal) from emp group by job;
+-----------+-------------+
| job | avgsal |
+-----------+-------------+
| ANALYST | 3000.000000 |
| CLERK | 1037.500000 |
| MANAGER | 2758.333333 |
| PRESIDENT | 5000.000000 |
| SALESMAN | 1400.000000 |
+-----------+-------------+t表
# 第二步,子查询
select
t.*, s.grade
from
(select job,avg(sal) as avgsal from emp group by job) t
join
salgrade s
on
t.avgsal between s.losal and s.hisal;
+-----------+-------------+-------+
| job | avgsal | grade |
+-----------+-------------+-------+
| CLERK | 1037.500000 | 1 |
| SALESMAN | 1400.000000 | 2 |
| ANALYST | 3000.000000 | 4 |
| MANAGER | 2758.333333 | 4 |
| PRESIDENT | 5000.000000 | 5 |
+-----------+-------------+-------+
select中的子查询
select后的子查询一次只能返回一条结果,多余一条就将报错!!
案例:找出每个员工的部门名称,要求显示员工名,部门名
select
e.ename,e.deptno,(select d.dname from dept d where e.deptno = d.deptno) as dname
from
emp e;
+--------+--------+------------+
| ename | deptno | dname |
+--------+--------+------------+
| SMITH | 20 | RESEARCH |
| ALLEN | 30 | SALES |
| WARD | 30 | SALES |
| JONES | 20 | RESEARCH |
| MARTIN | 30 | SALES |
| BLAKE | 30 | SALES |
| CLARK | 10 | ACCOUNTING |
| SCOTT | 20 | RESEARCH |
| KING | 10 | ACCOUNTING |
| TURNER | 30 | SALES |
| ADAMS | 20 | RESEARCH |
| JAMES | 30 | SALES |
| FORD | 20 | RESEARCH |
| MILLER | 10 | ACCOUNTING |
+--------+--------+------------+
union合并
以下几条sql语句的结果是一样的:
# 1
select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN';
# 2
select ename,job from emp where job in('MANAGER','SALESMAN');
# 3
select ename,job from emp where job = 'MANAGER'
union
select ename,job from emp where job = 'SALESMAN';
但是union的效率要比表连接高多了,每连接一次新表,则按照笛卡尔积现象,匹配次数都要乘新表的行数;而使用union连接,每次查询的效率是加法运算。
但是,在使用union时,要注意:
- 连接的两个结果集的列数应该相同
- 结果集合并时,列与列的数据类型也要一致
limit
用法
limit可以将结果集的一部分取出来,用作分页查询,提高用户体验。
用法:
limit 起始下标,长度
mysql中的limit在order by之后执行。
例如,取出工资排名在[3-5]名的员工?
select
ename,sal
from
emp
order by
sal desc
limit
2, 3; # 2表示起始位置从下标2开始,就是第三条记录。3表示长度。
+-------+---------+
| ename | sal |
+-------+---------+
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
分页
每页显示pageSize条记录
第pageNo页:limit (pageNo - 1) * pageSize , pageSize
每页显示3条记录:
第1页:limit 0,3 [0 1 2]
第2页:limit 3,3 [3 4 5]
第3页:limit 6,3 [6 7 8]
第4页:limit 9,3 [9 10 11]
DQL总结
至此,DQL语句已经全部学完了,这些关键字的执行顺序为:
1.from
2.where
3.group by
4.having
5.select
6.order by
7.limit…
DDL语句
表的创建
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型
);
表名:建议以t_ 或者 tbl_开始,可读性强。
数据类型
1、varchar(最长255byte):
可变长度的字符串
比较智能,节省空间。
会根据实际的数据长度动态分配空间。
优点:节省空间
缺点:需要动态分配空间,速度慢。
2、char(最长255byte):
定长字符串
不管实际的数据长度是多少。
分配固定长度的空间去存储数据。
使用不恰当的时候,可能会导致空间的浪费。
优点:不需要动态分配空间,速度快。
缺点:使用不当可能会导致空间的浪费。
固定长度的字符串选择char,长度不固定的选择varchar
3、int(最长11byte):整形
4、bigint:long长整型
5、float:单精度浮点型数据
6、double:双精度浮点型数据
7、date:短日期类型
8、datetime:长日期类型
9、clob:
字符大对象
最多可以存储4G的字符串。
比如:存储一篇文章,存储一个说明。
超过255个字符的都要采用CLOB字符大对象来存储。
Character Large OBject:CLOB
10、blob:
二进制大对象
Binary Large OBject
专门用来存储图片、声音、视频等流媒体数据。
往BLOB类型的字段上插入数据的时候,例如插入一个图片、视频等,你需要使用IO流才行。
DML语句
插入数据insert
insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3);
- 字段名要和值一一对应!数量、数据类型都要对应
- 如果有未指定字段名,插入成功后值默认是null。
- 如果前面的字段名都省略了的话,等于都写上了,所以后面的对应值也都要写上
insert插入日期:见上一篇单行处理函数
修改update
update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3... where 条件;
如果不加条件,整张表都会被更新!
update t_user set name = 'jack', birth = '2000-10-11' where id = 2;
删除数据delete
delete from 表名 where 条件;
如果不设置条件,整整表都会被删除!
delete from t_user where id = 2;