记录MySQL的学习笔记
7.9
DB,DBMS,SQL
数据库,数据库管理系统,以及SQL之间的关系:数据库即database(DB),数据库管理系统(DBMS)包括MySQl,
,Oracle,DB2等,数据库管理系统可以对数据库进行增删查改等操作处理数据库数据,SQL:结构化查询语言。
数据库管理系统通过执行SQL语句来操作数据库。
SQL语句的分类
SQL语句可分为:
DQL:
数据查询语言(凡是带有select关键字的都是查询语句)
select…
DML:
数据操作语言(凡是对表当中的数据进行增删改的都是DML)
insert delete update
insert 增
delete 删
update 改
这个主要是操作表中的数据data。
DDL:
数据定义语言
凡是带有create、drop、alter的都是DDL。
DDL主要操作的是表的结构。不是表中的数据。
create:新建,等同于增
drop:删除
alter:修改
这个增删改和DML不同,这个主要是对表结构进行操作。
TCL:
不是王牌电视。
是事务控制语言
包括:
事务提交:commit;
事务回滚:rollback;
DCL:
是数据控制语言。
例如:授权grant、撤销权限revoke….
DQl的一些语法
1.null很特殊,因为null表示什么也没有,所以在比较时不能用 xxx=bull而因该用xxx is null 或者 xxx is not null
2.单行处理函数:lower() 转换小写
upper()转换大写
substr(xxx,a,b) 截取子串,xxx为被提取的字符串,a为骑士位置,并且第一个字符的位置为1,b为截取的长度
concat(xxx,yyy)拼接xxx和yyy两个字符串
length()取长度
trim() 去空格
str_to_date() 将字符串转换成日期
date_format() 格式化日期
format() 设置千分位
round()四舍五入
rand()随机数
ifnull(数据, 被当做哪个值) 如果“数据”为NULL的时候,把这个数据结构当做哪个值。
3.分组函数(多行处理函数)
count()计数 sum()求和 avg()求平均值 max()求最大值 min()求最小值
分组函数即为多个输入一个输出。
DQL的基本结构为:
select
…
from
…
where
…
group by
…
having
…
order by
执行顺序:
1.from
2.where
3.group by
4.having
5.select
6.order by
DQL语法注意事项:
在where里不能直接使用分组函数,因为分组函数在使用的时候必须先分组之后才能使用。根据DQL的执行顺序,在执行where时,还未进行分组,所以无法使用分组函数,而在select里可以直接使用是因为,就算没有写group by数据库也会被默认分为一组,所以在select里可以直接使用分组函数。
7.10
内,外连接
DQL查询在涉及到多张表的查询时有多种查询方式,其中包括内连接,外连接等。
查询的语法为:
select
…
from
a
join //表示连接
b
on
a和b的连接条件
where
筛选条件
内外连接中还包括一种自连接:自连接的技巧在于将一张表看做两张表,依靠取别名来区分,
select
a.ename as ‘员工名’, b.ename as ‘领导名’
from
emp a
join
emp b
on
a.mgr = b.empno;
外连接具有right 和left两个关键字,在right右边的表或在left左边的表即为主表,主表中的所有数据都表示出来。
多表连接
三张表,四张表怎么连接的方式:
语法:
select
…
from
a
join
b
on
a和b的连接条件
join
c
on
a和c的连接条件
right join
d
on
a和d的连接条件
其相当于a与b,c分别内连接,与d右连接。
7.11
子查询
什么是子查询?
select语句中嵌套select语句,被嵌套的select语句称为子查询。
where子句中的子查询
案例:找出比最低工资高的员工姓名和工资?
select
ename,sal
from
emp
where
sal > min(sal);
ERROR 1111 (HY000): Invalid use of group function
where子句中不能直接使用分组函数。
实现思路:
第一步:查询最低工资是多少
select min(sal) from emp;
+----------+
| min(sal) |
+----------+
| 800.00 |
+----------+
第二步:找出>800的
select ename,sal from emp where sal > 800;
第三步:合并
select ename,sal from emp where sal > (select min(sal) from emp);
from子句中的子查询
注意: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表
第二步:把以上的查询结果就当做一张真实存在的表t。
mysql> select * from salgrade; s表
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
t表和s表进行表连接,条件:t表avg(sal) between s.losal and s.hisal;
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 |
+-----------+-------------+-------+
union合并查询结果集
查询工作岗位是MANAGER和SALESMAN的员工?
1 | select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN'; |
union能够提高效率,union的效率要高一些。对于表连接来说,每连接一次新表,
则匹配的次数满足笛卡尔积,成倍的翻。。。
但是union可以减少匹配的次数。在减少匹配次数的情况下,
还可以完成两个结果集的拼接。
a 连接 b 连接 c
a 10条记录
b 10条记录
c 10条记录
匹配次数是:1000
a 连接 b一个结果:10 * 10 –> 100次
a 连接 c一个结果:10 * 10 –> 100次
使用union的话是:100次 + 100次 = 200次。(union把乘法变成了加法运算)
union在进行结果集合并的时候,要求两个结果集的列数相同。
limit
完整用法:limit startIndex, length
startIndex是起始下标,length是长度。
起始下标从0开始。
缺省用法:limit 5; 这是取前5.
按照薪资降序,取出排名在前5名的员工?
select
ename,sal
from
emp
order by
sal desc
limit 5; //取前5
select
ename,sal
from
emp
order by
sal desc
limit 0,5;
因为每一个数据的起始位置为0,这个要与substr进行区分,所以当用limit来进行分页时,就有一个公式:
1 | limit (pageNo-1)*pageSize , pageSize |
结合所有,对DQL语句进行的一个大总结:
1 | select |
7.12
表的创建
建表的语法格式:(建表属于DDL语句,DDL包括:create drop alter)
create table 表名(字段名1 数据类型, 字段名2 数据类型, 字段名3 数据类型);
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型
);
表名:建议以t_ 或者 tbl_开始,可读性强。见名知意。
字段名:见名知意。
表名和字段名都属于标识符。
关于mysql中的数据类型?
varchar(最长255)
可变长度的字符串
比较智能,节省空间。
会根据实际的数据长度动态分配空间。
优点:节省空间
缺点:需要动态分配空间,速度慢。
char(最长255)
定长字符串
不管实际的数据长度是多少。
分配固定长度的空间去存储数据。
使用不恰当的时候,可能会导致空间的浪费。
优点:不需要动态分配空间,速度快。
缺点:使用不当可能会导致空间的浪费。
varchar和char我们应该怎么选择?
性别字段你选什么?因为性别是固定长度的字符串,所以选择char。
姓名字段你选什么?每一个人的名字长度不同,所以选择varchar。
int(最长11)
数字中的整数型。等同于java的int。
bigint
数字中的长整型。等同于java中的long。
float
单精度浮点型数据
double
双精度浮点型数据
date
短日期类型
datetime
长日期类型
clob
字符大对象
最多可以存储4G的字符串。
比如:存储一篇文章,存储一个说明。
超过255个字符的都要采用CLOB字符大对象来存储。
Character Large OBject:CLOB
blob
二进制大对象
Binary Large OBject
专门用来存储图片、声音、视频等流媒体数据。
往BLOB类型的字段上插入数据的时候,例如插入一个图片、视频等,
你需要使用IO流才行。
插入数据insert (DML)
语法格式:
insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3);
注意:字段名和值要一一对应。什么是一一对应?
数量要对应。数据类型要对应。
insert into t_student(no,name,sex,age,email) values(1,'zhangsan','m',20,'zhangsan@123.com');
insert into t_student(email,name,sex,age,no) values('lisi@123.com','lisi','f',20,2);
insert into t_student(no) values(3);
+------+----------+------+------+------------------+
| no | name | sex | age | email |
+------+----------+------+------+------------------+
| 1 | zhangsan | m | 20 | zhangsan@123.com |
| 2 | lisi | f | 20 | lisi@123.com |
| 3 | NULL | NULL | NULL | NULL |
+------+----------+------+------+------------------+
insert into t_student(name) values('wangwu');
+------+----------+------+------+------------------+
| no | name | sex | age | email |
+------+----------+------+------+------------------+
| 1 | zhangsan | m | 20 | zhangsan@123.com |
| 2 | lisi | f | 20 | lisi@123.com |
| 3 | NULL | NULL | NULL | NULL |
| NULL | wangwu | NULL | NULL | NULL |
+------+----------+------+------+------------------+
注意:insert语句但凡是执行成功了,那么必然会多一条记录。
没有给其它字段指定值的话,默认值是NULL。
drop table if exists t_student;
create table t_student(
no int,
name varchar(32),
sex char(1) default 'm',
age int(3),
email varchar(255)
);
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| no | int(11) | YES | | NULL | |
| name | varchar(32) | YES | | NULL | |
| sex | char(1) | YES | | m | |
| age | int(3) | YES | | NULL | |
| email | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
insert into t_student(no) values(1);
mysql> select * from t_student;
+------+------+------+------+-------+
| no | name | sex | age | email |
+------+------+------+------+-------+
| 1 | NULL | m | NULL | NULL |
+------+------+------+------+-------+
insert语句中的“字段名”可以省略吗?可以
insert into t_student values(2); //错误的
// 注意:前面的字段名省略的话,等于都写上了!所以值也要都写上!
insert into t_student values(2, 'lisi', 'f', 20, 'lisi@123.com');
+------+------+------+------+--------------+
| no | name | sex | age | email |
+------+------+------+------+--------------+
| 1 | NULL | m | NULL | NULL |
| 2 | lisi | f | 20 | lisi@123.com |
+------+------+------+------+--------------+
insert语句可以一次插入多条记录
语法:insert into t_user(字段名1,字段名2) values(),(),(),();
一次可以插入多条记录:
insert into t_user(id,name,birth,create_time) values
(1,'zs','1980-10-11',now()),
(2,'lisi','1981-10-11',now()),
(3,'wangwu','1982-10-11',now());
修改update(DML)
语法格式:
update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3… where 条件;
注意:没有条件限制会导致所有数据全部更新。
update t_user set name = 'jack', birth = '2000-10-11' where id = 2;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 1990-10-01 | 2020-03-18 15:49:50 |
| 2 | jack | 2000-10-11 | 2020-03-18 15:51:23 |
+------+----------+------------+---------------------+
update t_user set name = 'jack', birth = '2000-10-11', create_time = now() where id = 2;
更新所有?
update t_user set name = 'abc';
删除数据 delete (DML)
语法格式?
delete from 表名 where 条件;
注意:没有条件,整张表的数据会全部删除!
delete from t_user where id = 2;
insert into t_user(id) values(2);
delete from t_user; // 删除所有!
delete语句删除数据的原理?(delete属于DML语句!!!)
表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放!!!
这种删除缺点是:删除效率比较低。
这种删除优点是:支持回滚,后悔了可以再恢复数据!!!
truncate语句删除数据的原理?
这种删除效率比较高,表被一次截断,物理删除。
这种删除缺点:不支持回滚。
这种删除优点:快速。
用法:truncate table dept_bak; (这种操作属于DDL操作。)
drop table 表名; // 这不是删除表中的数据,这是把表删除。
7.13
对表结构的修改需要使用:alter
属于DDL语句
DDL包括:create drop alter
约束
约束对应的英语单词:constraint
在创建表的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的
完整性、有效性!!!
约束的作用就是为了保证:表中的数据有效!!
约束包括哪些?
非空约束:not null
唯一性约束: unique
主键约束: primary key (简称PK)
外键约束:foreign key(简称FK)
检查约束:check(mysql不支持,oracle支持)
not null
非空约束not null约束的字段不能为NULL。
create table t_vip(
id int,
name varchar(255) not null // not null只有列级约束,没有表级约束!
);
unique
唯一性约束unique约束的字段不能重复,但是可以为NULL。
create table t_vip(
id int,
name varchar(255) unique,
email varchar(255)
);
name和email两个字段联合起来具有唯一性!!!!
create table t_vip(
id int,
name varchar(255),
email varchar(255),
unique(name,email) // 约束没有添加在列的后面,这种约束被称为表级约束。
);
在mysql当中,如果一个字段同时被not null和unique约束的话,该字段自动变成主键字段。
主键约束
主键约束(primary key,简称PK)
主键约束的相关术语?
主键约束:就是一种约束。
主键字段:该字段上添加了主键约束,这样的字段叫做:主键字段
主键值:主键字段中的每一个值都叫做:主键值。
什么是主键?有啥用?
主键值是每一行记录的唯一标识。
主键值是每一行记录的身份证号!!!
记住:任何一张表都应该有主键,没有主键,表无效,并且一张表只有一个主键!!
主键的特征:not null + unique(主键值不能是NULL,同时也不能重复!)
创建主键约束:
create table t_vip(
id int primary key, //列级约束
name varchar(255)
);
外键约束
外键约束(foreign key,简称FK)
外键约束涉及到的相关术语:
外键约束:一种约束(foreign key)
外键字段:该字段上添加了外键约束
外键值:外键字段当中的每一个值。
一张表可以有多个FK, FK主要用来优化数据库,解决数据库冗余的问题,避免空间的浪费。被外键约束的字段可以重复,但是数据都必须是主表字段里的数据,不能出现其他的数据。
存储引擎
存储引擎是MySQL中特有的一个术语,其它数据库中没有。实际上存储引擎是一个表存储/组织数据的方式。不同的存储引擎,表存储数据的方式不同。
可以在建表的时候给表指定存储引擎。
1 | CREATE TABLE `t_student` ( |
在建表的时候可以在最后小括号的”)”的右边使用:
ENGINE来指定存储引擎。
CHARSET来指定这张表的字符编码方式。
结论:
mysql默认的存储引擎是:InnoDB
mysql默认的字符编码方式是:utf8
使用show engines \G查看mysql支持哪些存储引擎。
MyISAM存储引擎?
它管理的表具有以下特征:
使用三个文件表示每个表:
格式文件 — 存储表结构的定义(mytable.frm)
数据文件 — 存储表行的内容(mytable.MYD)
索引文件 — 存储表上索引(mytable.MYI):索引是一本书的目录,缩小扫描范围,提高查询效率的一种机制。
可被转换为压缩、只读表来节省空间
提示一下:
对于一张表来说,只要是主键,
或者加有unique约束的字段上会自动创建索引。
MyISAM存储引擎特点:
可被转换为压缩、只读表来节省空间
这是这种存储引擎的优势!!!!
MyISAM不支持事务机制,安全性低。
InnoDB存储引擎?
这是mysql默认的存储引擎,同时也是一个重量级的存储引擎。
InnoDB支持事务,支持数据库崩溃后自动恢复机制。
InnoDB存储引擎最主要的特点是:非常安全。
它管理的表具有下列主要特征:
– 每个 InnoDB 表在数据库目录中以.frm 格式文件表示
– InnoDB 表空间 tablespace 被用于存储表的内容(表空间是一个逻辑名称。表空间存储数据+索引。)
– 提供一组用来记录事务性活动的日志文件
– 用 COMMIT(提交)、SAVEPOINT 及ROLLBACK(回滚)支持事务处理
– 提供全 ACID 兼容
– 在 MySQL 服务器崩溃后提供自动恢复
– 多版本(MVCC)和行级锁定
– 支持外键及引用的完整性,包括级联删除和更新
InnoDB最大的特点就是支持事务:
以保证数据的安全。效率不是很高,并且也不能压缩,不能转换为只读,
不能很好的节省存储空间。
MEMORY存储引擎?
使用 MEMORY 存储引擎的表,其数据存储在内存中,且行的长度固定,
这两个特点使得 MEMORY 存储引擎非常快。
MEMORY 存储引擎管理的表具有下列特征:
– 在数据库目录内,每个表均以.frm 格式的文件表示。
– 表数据及索引被存储在内存中。(目的就是快,查询快!)
– 表级锁机制。
– 不能包含 TEXT 或 BLOB 字段。
MEMORY 存储引擎以前被称为HEAP 引擎。
MEMORY引擎优点:查询效率是最高的。不需要和硬盘交互。
MEMORY引擎缺点:不安全,关机之后数据消失。因为数据和索引都是在内存当中。
事务
一个事务其实就是一个完整的业务逻辑。是一个最小的工作单元。不可再分。
只有DML语句才会有事务这一说,其它语句和事务无关!insert,delete,update只有以上的三个语句和事务有关系,其它都没有关系。
提交事务:commit; 回滚事务:rollback; 事务对应的英语单词是:transaction
mysql默认情况下是支持自动提交事务的。(自动提交)
什么是自动提交?每执行一条DML语句,则提交一次!
事务包括4个特性?
A:原子性
说明事务是最小的工作单元。不可再分。
C:一致性
所有事务要求,在同一个事务当中,所有操作必须同时成功,或者同时失败,
以保证数据的一致性。
I:隔离性
A事务和B事务之间具有一定的隔离。
教室A和教室B之间有一道墙,这道墙就是隔离性。
A事务在操作一张表的时候,另一个事务B也操作这张表会那样???
D:持久性
事务最终结束的一个保障。事务提交,就相当于将没有保存到硬盘上的数据
保存到硬盘上!
事务的隔离性
1 | 读未提交:read uncommitted(最低的隔离级别)《没有提交就读到了》 |
7.14
索引
什么是索引?
索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。
一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。
索引相当于一本书的目录,是为了缩小扫描范围而存在的一种机制。
对于一本字典来说,查找某个汉字有两种方式:
第一种方式:一页一页挨着找,直到找到为止,这种查找方式属于全字典扫描。
效率比较低。
第二种方式:先通过目录(索引)去定位一个大概的位置,然后直接定位到这个
位置,做局域性扫描,缩小扫描的范围,快速的查找。这种查找方式属于通过
索引检索,效率较高。
创建索引:
1 | mysql> create index emp_ename_index on emp(ename); |
删除索引:
mysql> drop index emp_ename_index on emp;
将emp表上的emp_ename_index索引对象删除。
在mysql当中,怎么查看一个SQL语句是否使用了索引进行检索?
mysql> explain select * from emp where ename = 'KING';
失效的第1种情况:
select * from emp where ename like ‘%T’;
失效的第2种情况:
使用or的时候会失效,如果使用or那么要求or两边的条件字段都要有
索引,才会走索引,如果其中一边有一个字段没有索引,那么另一个
字段上的索引也会实现。所以这就是为什么不建议使用or的原因。
失效的第3种情况:
使用复合索引的时候,没有使用左侧的列查找,索引失效
什么是复合索引?
两个字段,或者更多的字段联合起来添加一个索引,叫做复合索引。
比如create index emp_job_sal_index on emp(job,sal);
当执行select * from emp where job = ‘MANAGER’;有索引。当执行select * from emp where sal = 800;时,无索引。
失效的第4种情况:
在where当中索引列使用了函数
explain select * from emp where lower(ename) = ‘smith’;
索引在数据库当中分了很多类?
单一索引:一个字段上添加索引。
复合索引:两个字段或者更多的字段上添加索引。
主键索引:主键上添加索引。
唯一性索引:具有unique约束的字段上添加索引。
…..
注意:唯一性比较弱的字段上添加索引用处不大。
视图
什么是视图?
view:站在不同的角度去看待同一份数据。
我们可以面向视图对象进行增删改查,对视图对象的增删改查,会导致原表被操作!(视图的特点:通过对视图的操作,会影响到原表数据。)
创建视图对象:
1 | create view dept2_view as select * from dept2; |
1 | create view |
在as后加上一个DQL语句
删除视图对象:
drop view dept2_view;
//面向视图查询
select * from dept2_view;
// 面向视图插入
insert into dept2_view(deptno,dname,loc) values(60,’SALES’, ‘BEIJING’);
// 面向视图删除
mysql> delete from dept2_view;
视图相当于一个引用,他可以简化SQL语句,当要重复执行一个复杂的SQL语句时,就可以用视图来代替。
数据库三范式
数据库设计范式共有?
3个。
第一范式:要求任何一张表必须有主键,每一个字段原子性不可再分。(最核心,最重要的范式,所有表的设计都需要满足。
必须有主键,并且每一个字段都是原子性不可再分。)
第二范式:建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,
不要产生部分依赖。(建立在第一范式的基础之上,要求所有非主键字段必须完全依赖主键,不要产生部分依赖。例如主键是复合主键,而其他非主键字段,只对其中一个主键对应。)
此时为多对多的关系 设计理念:多对多,三张表,关系表两个外键
第三范式:建立在第二范式的基础之上,要求所有非主键字段直接依赖主键,
不要产生传递依赖。(第三范式建立在第二范式的基础之上,要求所有非主键字典必须直接依赖主键,不要产生传递依赖。例如两个非主键字段A,B都对主键完全依赖,但是,A,B却是完全对应的,可以完全通过A对应出B)
此时为一对多的关系 设计理念:一对多,两张表,多的表加外键
设计数据库表的时候,按照以上的范式进行,可以避免表中数据的冗余,空间的浪费。
但是数据库设计三范式是理论上的。实践和理论有的时候有偏差。最终的目的都是为了满足客户的需求,有的时候会拿冗余换执行速度。因为在sql当中,表和表之间连接次数越多,效率越低。(笛卡尔积)有的时候可能会存在冗余,但是为了减少表的连接次数,这样做也是合理的,并且对于开发人员来说,sql语句的编写难度也会降低。