您现在的位置是:首页 >技术杂谈 >mysql从零开始(2)网站首页技术杂谈

mysql从零开始(2)

back2childhood 2024-06-07 00:00:03
简介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;
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。