1. DQL语言的学习
① 基础查询
/*
语法:
select 查询列表
from 表名;
特点:
① 通过select查询完的结果 ,是一个虚拟的表格,不是真实存在
② 要查询的东西 可以是常量值、可以是表达式、可以是字段、可以是函数
③ 可以没有from语句
④ 先执行from语句,再执行select查询
*/
#?查询单个字段
select 字段名
from 表名;
#?查询多个字段
select 字段1,字段2,...,字段n
from 表名;
#?查询所有字段(查询整个表数据)
select *
from 表名; #虽然这种方式比较简单,但是为了提高可读性,建议不使用*,而是列出所有字段。
#?查询时给字段起别名(as)
select 字段1 【as】 别名1,字段2 【as】 别名2...
from 表; #其中as可以省略,直接用空格
#?查询结果去重(distinct)
select distinct 字段
from 表;
② 条件查询
/* 条件查询:根据条件过滤原始表的数据,查询到想要的数据
语法:
select 查询列表
from 表名
where 筛选条件;
特点:先执行from语句,在执行where语句,最后执行select语句
分类:
一、?条件表达式
> < >= <= = != <> <=>安全等于
between 值1 and 值2 筛选所需要的值在值1和值2之间,等同于 >=值1 and <=值2
is null /is not null 用于判断null值(也只能判断null值)
in / not in in是指包含,后面接(值1,值2...),相当于多个or,但效率更高
注意:安全等于<=>可以判断null值,而=不能判断null值
示例:筛选学生表中:姓名为张三的所有信息。
select *
from students
where name=‘张三‘;
二、?逻辑表达式
and(&&):两个条件如果同时成立,结果为true,否则为false
or(||):两个条件只要有一个成立,结果为true,否则为false
not(!):如果条件成立,则not后为false,否则为true
示例:筛选学生表中:分数在60和70之间的学生全部信息。
select *
from students
where score>=60 and scord<=70;
三、?模糊查询
like: 通常搭配通配符使用
通配符:%任意多个字符,_任意单个字符(%不能表示null)
示例:筛选学生表中:姓名第二个字为伟的学生全部信息
select *
from students
where name like ‘_伟%‘;
*/
③ 排序查询
/* 排序查询:对查询的结果按某一字段进行排序。
语法:
select 查询列表
from 表
【where 筛选条件】
order by 排序的字段|表达式|函数|别名 【asc|desc】;
特点:
① 可以没有where筛选语句
② asc值升序,desc指降序,如果不写默认为升序
③ 排序列表支持单个字段、多个字段、函数、表达式、别名
④ order by的位置一般放在查询语句的最后(除limit语句之外)
⑤ 先执行from语句,再执行where语句,然后执行select,最后执行order by排序
*/
#示例:查询学生表中:所有姓张的学生全部信息,并按照考试成绩进行降序排列
select *
from students
where name like ‘张%‘
order by score desc;
④ 常见函数
1) 单行函数
-
concat: 将多个字段/字符进行拼接。
#语法:concat(字段/字符1,字段/字符2,...,字段/字符n) #示例:查询学生表中:所有学生的姓名和成绩,并显示为一列,格式示范:张三(98分) select concat(name,‘(‘,score,‘分)‘) as 姓名(分数) from students;
-
ifnull:判断某字段或表达式是否为null,如果为null 返回指定的值,否则返回原本的值
#语法:ifnull(字段/表达式,指定值) #示例:查询学生表中:所有学生的姓名和成绩,并将原来成绩为null(没参加考试)的同学成绩改为0分 select name,ifnull(score,0) from students;
-
isnull:判断某字段或表达式是否为null,如果是,则返回1,否则返回0
#语法:ifnull(字段/表达式) #示例:查询学生表中:所有学生的姓名以及是否缺考,如果缺考记为1,否则记为0 select name,ifnull(score) from students;
-
substr:截取子串
#语法:substr(字段/字符,初始索引,截取字符长度) #注意:字符串索引从1开始,而不是从0开始,如果截取字符长度省略,则截取到最后。 #示例:截取一个字符串的前三个字母 select substr(‘zhang‘,1,3); #查询结果为zha
-
length :获取字节个数
#语法:length(字段/字符) #注意:获取的是字节个数,而不是字符个数,在utf8编码中,1个汉字为3个字节,1个字母为1个字节。 #示例: select length(‘123张‘); #查询结果为6
-
instr:返回子串第一次出现的索引
#语法:instr(字段/字符,子串) #注意:如果字串不在原字符中,则返回0 #示例: select instr(‘123六六456‘,‘六六‘); #查询结果为4 select instr(‘123六六456‘,‘六六六‘); #查询结果为0
-
round:四舍五入
#语法:round(数字,保留小数位数) #注意:保留小数位数可以不写,那么默认四舍五入为整数。 #示例: select round(4.76,1); #查询结果为4.8
-
truncate:截断
#语法:truncate(数字,保留小数位数) #注意:保留小数位数可以不写,那么默认截断为整数。截断不是四舍五入,而是均舍掉,4.1、4.9截断均为4。 #示例: select truncate(4.76,1); #查询结果为4.7
-
rand:0-1之间随机数
#语法:rande() #示例: select rand(); #返回一个范围在0-1之间的随机值
-
floor:向下取整
#语法:floor(数字) #注意:返回一个不大于括号中值的最大整数。 #示例: select floor(4.7); #查询结果为4
-
ceil:向上取整
#语法:floor(数字) #注意:返回一个不小于括号中值的最大整数。 #示例: select ceil(4.7); #查询结果为5
-
mod:取余
#语法:mod(数1,数2); #注意:返回结果为数1除以数2所得的余数。 #示例: SELECT MOD(10,3); #查询结果为1
-
now:当前系统日期+时间
#语法:now(); #示例: SELECT now(); #查询结果为:2020-07-08 16:43:35
-
curdate:当前系统日期
#语法:curdate(); #示例: SELECT curdate(); #查询结果为:2020-07-08
-
curtime:当前系统时间
#语法:curtime(); #示例: SELECT curtime(); #查询结果为:16:45:28
-
str_to_date:将字符转换成日期
#语法:str_to_date(字符,日期格式); #注意:%Y是年,%m是月,%d是日,%H是小时,%i是分,%s是秒 #示例: select str_to_date(‘2020-7-8‘,‘%Y-%m-%d‘); #查询结果为:2020-07-08
-
date_format:将日期转换成字符
#语法:date_format(日期,日期格式); #注意:%Y是年,%m是月,%d是日,%H是小时,%i是分,%s是秒 #示例: select date_format(‘2020-7-8‘,‘今天是%Y年%m月%d日‘)); #查询结果为:今天是2020年07月08日
-
其他日期函数
select date(now()); #返回日期,结果为:2020-07-08 select year(now()); #返回年,结果为:2020 select month(now()); #返回月 select day(now()); #返回日 select minute(now()); #返回分钟 select second(now()); #返回秒 select datediff(‘2020-08-08‘,‘2020-07-08‘):#返回两个日期相差的天数,结果为:31
2)分组函数/聚集函数
聚集函数:作用于一组函数,最后返回一个值
分类:
- sum() 求和
- min() 最小值
- max() 最大值
- avg() 平均值
- count() 计数
#示例:查询学生表中,学生成绩的总和、最小值、最大值、平均成绩以及学生总人数
select sum(score),min(score),max(score),avg(score),count(*)
from students;
特点:
- 以上五个分组函数都忽略null值,除了count(*);
- sum和avg一般用于处理数值型,max、min、count可以处理任何数据类型;
- 都可以搭配distinct使用,用于统计去重后的结果。
⑤ 分组查询
/* 分组查询:将查询结果按照1个或多个字段进行分组,字段值相同的为一组。
语法:
select 查询的字段,分组函数
from 表
【where 分组前的筛选条件】
group by 分组的字段
【having 分组后的筛选条件】
【order by 排序】
特点:
① where语句、having语句和order by语句可以没有;
② 可以按单个字段分组,也可以按多个字段分组,字段之间用逗号隔开;
③ 和分组函数一同查询的字段最好是分组后的字段;
④ 分组筛选
where 在分组前对原始表进行筛选,位于group by的前面
havng 在分组后对分组后的结果集进行筛选,位于group by的后面
⑤ having后可以支持别名;
⑥ 先执行from,再执行where,然后执行group by,having,接着执行select,最后执行order by。
*/
#示例:查询学生表中,每个班级的平均分数,并根据此进行降序排列
select avg(score) as 平均分数,grade as 班级名
from students
group by grade
order by avg(score);
⑥ 连接查询
连接查询:所要查询的内容在多个表中,对多个表进行连接后查询
笛卡尔乘积:如果连接条件省略或无效则会出现。检索出的行数目等于第一个表中的行数乘以第二个表的行数。
解决办法:添加上连接条件
SQL92语法(了解):支持内连接(等值连接、非等值连接、自连接)
-
等值连接
/* 语法: select 查询列表 from 表1 别名,表2 别名 where 表1.key=表2.key 【and 筛选条件】 【group by 分组字段】 【having 分组后的筛选】 【order by 排序字段】 特点: ① 一般为表起别名; ② 多表的顺序可以调换;; ③ n表连接至少需要n-1个连接条件; ④ 等值连接的结果是多表的交集部分。 */
-
非等值连接
/* 语法: select 查询列表 from 表1 别名,表2 别名 where 非等值的连接条件 【and 筛选条件】 【group by 分组字段】 【having 分组后的筛选】 【order by 排序字段】 */
-
自连接
/* 语法: select 查询列表 from 表 别名1,表 别名2 where 等值的连接条件 【and 筛选条件】 【group by 分组字段】 【having 分组后的筛选】 【order by 排序字段】 */
SQL99语法?(重点):支持内连接(等值连接、非等值连接、内连接)、外连接(左外、右外、全外)和交叉连接。
-
内连接
/* 语法: select 字段,... from 表1 【inner】 join 表2 on 连接条件 【inner】 join 表3 on 连接条件 ... 【where 筛选条件】 【group by 分组字段】 【having 分组后的筛选条件】 【order by 排序的字段或表达式】 特点: ① 一般为表起别名; ② 多表的顺序可以调换; ③ n表连接至少需要n-1个连接条件; ④ 内连接的结果是多表的交集部分??; ⑤ inner关键字可以省略; ⑥ 先执行from,再执行join on,接着where,之后group by having,然后select,最后order by。 */
-
外连接
/* 语法: select 字段,... from 表1 left/right/full 【outer】 join 表2 on 连接条件 left/right/full 【outer】 join 表3 on 连接条件 ... 【where 筛选条件】 【group by 分组字段】 【having 分组后的筛选条件】 【order by 排序的字段或表达式】 特点: ① 查询的结果=主表中所有的行,如果从表和它匹配的将显示匹配行,如果从表没有匹配的则显示null; ② 多表的顺序很重要,left join 左边的是主表,right join 右边的就是主表,full join 两边都是主表; ③ outer关键字可以省略。 */
-
交叉连接(不常用,关键字为cross join)
⑦ 子查询
/*
子查询:一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询
主查询:在外面的查询语句,称为主查询或外查询
特点:
① 子查询都放在小括号内;
② 子查询可以放在from后面、select后面、where后面、having后面,但一般放在条件的右侧;
③ 子查询优先于主查询执行,主查询使用了子查询的执行结果;
④ 子查询根据查询结果的行数不同分为以下两类:
- 单行子查询(结果集只有一行)
一般搭配单行操作符使用:> < = <> >= <=
非法使用子查询的情况:
a、子查询的结果为一组值
b、子查询的结果为空
- 多行子查询(结果集有多行)
一般搭配多行操作符使用:any、all、in、not in
in: 属于子查询结果中的任意一个就行
any和all往往可以用其他查询代替
*/
⑧ 分页查询
/*
应用场景:当要查询的条目数太多,一页显示不全
语法:
select 字段|表达式,...
from 表1
【连接类型 join 表2 on 连接条件】
【where 条件】
【group by 分组字段】
【having 条件】
【order by 排序的字段】
limit 【起始的条目索引,】条目数;
特点:
① 起始条目索引从0开始
② 其实条目索引可以省略,如省略默认为0
③ limit子句放在查询语句的最后;
④ 先执行from,再执行join on,接着where,再接着group by having,之后select,然后order by,最后limit。
*/
#示例:查询学生表中,分数位于前五的学生全部信息(假设前五名没有并列排名)
select *
from students
order by score desc
limit 5;
⑨ 联合查询
/*
union:合并、联合,将多次查询结果合并成一个结果集
语法:
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
.....
select 字段|常量|表达式|函数 【from 表】 【where 条件】
特点:
① 多条查询语句的查询的列数必须是一致的;
② 多条查询语句的查询的各列类型、顺序最好一致,各列数据类型也可以不一致,但必须兼容(可以隐含转换);
③ union代表去重,union all代表不去重。
*/
#示例(多个表):假设一班和二班均有一张成绩表,现在要把两张表的信息合并。
select name,score
from grade1
union
select name,score
from grade2;
#示例(一个表):查询学生表中:成绩大于90或者姓赵的同学的全部信息(要求用union不用or)
select *
from students
where score>90
union
select *
from students
where name like(‘赵%‘)
2. DML语言的学习
① 插入
/*
在表中插入数据,有两种方式。
?方式一(重点):
语法:
insert into 表名(字段1,...)
values(值1,...);
特点:
① 字段类型和值类型一致或兼容,而且一一对应;
② 字段的个数和顺序不一定与原始表中的字段个数和顺序一致,但必须保证值和字段一一对应;
③ 字段可以省略,默认为所有字段,并且顺序和表中的存储顺序一致;
④ 不可以为空的字段,必须插入值;
⑤ 假如表中有可以为null的字段,注意可以通过以下两种方式插入null值:字段和值都省略/字段写上,值使用null。
?方式二:
语法:
insert into 表名
set 字段1=值1,字段2=值2,...,字段n=值n;
?二者区别:
1).方式一支持一次插入多行,语法如下:
insert into 表名【(字段名,..)】
values(值,..),(值,...),...;
2).方式一支持子查询,语法如下:
insert into 表名
查询语句;
*/
#示例:在学生表中插入一条学生信息,学号:8,姓名:李四,班级:2,姓别:男,成绩:88,电话:123456789
#方式一
insert into students(id,name,grade,gender,score,phone)
values(8,‘李四‘,2,‘男‘,88,‘123456789‘);
#方式2
insert into students
set id=8,name=‘李四‘,grade=2,gender=‘男‘,score=88,phone=‘123456789‘;
② 修改
/*
语法:
update 表名
set 字段1=新值1,字段2=新值2,...
【where 条件】
特点:如果没有where筛选条件,则会更改表中所有行。
*/
#示例:在学生表中修改李四的成绩为90分
update students
set score=90
where name=‘李四‘;
③ 删除
/*
删除表中数据,有两种方式。
?方式一(重点):delete语句?
语法:
delete from 表名
【where 筛选条件】;
特点:
① 如果没有where筛选条件,则会删除表中所有行;
② delect删除的是表中的一行,而不是整个表,也不是一行中的某一个数据。
?方式二:truncate table语句
语法:
truncate table 表名
特点:
① truncate table不能删除某一行,而是删除表中所有数据;
② truncate table语句删除效率更高,其实质是删除原来的表,然后重建了新表,而不是逐行删除表数据。
?二者区别:
1).truncate table不能加where条件,而delete可以加where条件
2).truncate table 删除带自增长的列的表后,如果再插入数据,数据从1开始,
delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始。
3).truncate table删除不能回滚,delete删除可以回滚
*/
#示例:在学生表中删除李四的信息
#只能用方式一,不能用方式二
delete from students
where name=‘李四‘;
#示例:删除学生表中全部信息
#方式1
delete from students;
#方式2
truncate table students;
*/
3. DDL语言的学习
① 库和表的管理
库的管理:
/*
1)、创建库
create database 【if not exists】库名;
2)、删除库
drop database 【if exists】库名;
*/
表的管理:
1. 创建表 create table
/*
语法:
create table 【if not exists】 表名(
字段名 字段类型 【约束】,
字段名 字段类型 【约束】,
。。。
字段名 字段类型 【约束】
);
*/
#示例:创建一个学生表,包含学号、姓名、班级、性别、分数和电话号码
create table students(
id int,
name varchar(10),
grade int,
gender char(1),
score int,
phone varchar(20)
);
? 2. 修改表 alter table
/*
1).添加列
alter table 表名 add column 列名 类型 【first|after 字段名】;
2).修改列的类型或约束
alter table 表名 modify column 列名 新类型 【新约束】;
3).修改列名
alter table 表名 change column 旧列名 新列名 类型;
4).删除列
alter table 表名 drop column 列名;
5).修改表名(重命名表)
alter table 表名 rename 【to】 新表名;
*/
#示例:在学生表中添加一列用于显示email(邮箱)
alter table students add column email varchar(20);
#示例:将学生表中的电话号码类型改为int
alter table students modify column phone int;
#示例:将学生表中的name列名称改为stu_name
alter table students change column name stu_name varchar(20);
#示例:将学生表中的email列删除
alter table students drop column email;
#示例:将学生表名改为stu_tables
alter table students rename to stu_tables;
? 3. 删除表 drop table
#语法:drop table【if exists】 表名;
? 4. 复制表
/*
1)、复制表的结构
create table 表名 like 旧表;
2)、复制表的结构+数据
create table 表名
select 查询列表
from 旧表
【where 筛选】;
*/
② 常见类型
/*
?整型:tineint、smallint、mediumint、int/integer、bigint
特点:
①都可以设置无符号和有符号,默认有符号,通过unsigned设置无符号
②如果超出了范围,会报out or range异常,插入临界值
③长度可以不指定,默认会有一个长度,长度代表显示的最大宽度,如果不够则左边用0填充,
但需要搭配zerofill,并且默认变无符号整型
?小数:
浮点型:double(M,D),float(M,D)
定点型:decimal(M,D)或者简写为dec(M,D)
特点:
①M代表整数部位+小数部位的个数,D代表小数部位
②如果超出范围,则报out or range异常,并且插入临界值
③M和D都可以省略,但对于定点数,M默认为10,D默认为0
④如果精度要求较高,则优先考虑使用定点数
?字符型:char、varchar、binary、varbinary、enum、set、text、blob
特点:
①char:固定长度的字符,写法为char(M),最大长度不能超过M,其中M可以省略,默认为1
②varchar:可变长度的字符,写法为varchar(M),最大长度不能超过M,其中M不可以省略
?日期型:year年、date日期、time时间、datetime 日期+时间、timestamp 日期+时间
*/
③ 常见约束
/*含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性
?常见约束:
?NOT NULL:非空,该字段的值必填
?UNIQUE:唯一,该字段的值不可重复
?DEFAULT:默认,该字段的值如果不插入会有默认值
?CHECK:检查,mysql不支持
?PRIMARY KEY:主键,该字段的值不可重复并且非空 unique+not null
?FOREIGN KEY:外键,该字段的值引用了另外的表的字段
主键与唯一的区别:
①、一个表至多有一个主键,但可以有多个唯一;
②、主键不允许为空,唯一可以为空。
?创建表时添加约束
CREATE TABLE 表名(
字段名 字段类型 列级约束,
字段名 字段类型,
表级约束
)
如:
create table 表名(
字段名 字段类型 not null, #非空
字段名 字段类型 primary key, #主键
字段名 字段类型 unique, #唯一
字段名 字段类型 default 值, #默认
constraint 约束名 foreign key(字段名) references 主表(被引用列)
)
注意:
①表级约束语法:在各个字段的最下面【constraint 约束名】 约束类型(字段名)
特殊:【constraint 约束名】 foreign key(字段名) references 主表(被引用列)
表级约束的constraint 约束名可省略,如可以直接primary key(id)
②列级约束和表级约束的区别
支持类型 是否可以起约束名
列级约束 除了外键 不可以
表级约束 除了非空和默认 可以,但对主键无效
③列级约束可以在一个字段上追加多个,中间用空格隔开,没有顺序要求
?修改表时添加或删除约束
1、非空
添加非空
alter table 表名 modify column 字段名 字段类型 not null;
删除非空
alter table 表名 modify column 字段名 字段类型 ;
2、默认
添加默认
alter table 表名 modify column 字段名 字段类型 default 值;
删除默认
alter table 表名 modify column 字段名 字段类型 ;
3、主键
添加主键
alter table 表名 add【 constraint 约束名】 primary key(字段名);
删除主键
alter table 表名 drop primary key;
4、唯一
添加唯一
alter table 表名 add【 constraint 约束名】 unique(字段名);
删除唯一
alter table 表名 drop index 索引名;
5、外键
添加外键
alter table 表名 add【 constraint 约束名】 foreign key(字段名) references 主表(被引用列);
删除外键
alter table 表名 drop foreign key 约束名;
?自增长列
特点:
①不用手动插入值,可以自动提供序列值,默认从1开始,步长为1,可以通过下面语句改变步长:
set auto_increment_increment=值;
②一个表至多有一个自增长列
③自增长列只能支持数值型
④自增长列必须为一个key
一、创建表时设置自增长列
create table 表(
字段名 字段类型 约束 auto_increment
)
二、修改表时设置自增长列
alter table 表 modify column 字段名 字段类型 约束 auto_increment
三、删除自增长列
alter table 表 modify column 字段名 字段类型 约束
*/
4. DCL语言的学习
事务:一条或多条sql语句组成一个执行单位,这一组sql语句要么都执行,要么都不执行;
事务的特点:(ACID)
原子性(Atomicity):一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做;如果事务中一个sql语句执行失败,那么已执行的语句也会回滚,数据库退回到事务前的状态,就像这个事务从来没有执行过一样。
一致性(Consistency):事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。
隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改,一个事务的执行不受另外一个事务的干扰。
持久性(Durability ):事务一旦提交后,对数据的修改就是永久的,即便系统故障也不会丢失
事务的使用步骤:
/*
1.隐式事务:没有明显的开启和结束事务的标志,本身就是一条事务可以自动提交,比如insert、update、delete
2.显示事务:具有明显的开启和结束事务的标志.
1)、开启事务(取消自动提交事务的功能)
set autocommit=0;
start transaction; #可以省略
2)、编写事务的一组逻辑操作单元(多条sql语句)
支持insert、update、delete语句
【savepoint 回滚点名;】 #设置回滚点,可以没有
3)、提交事务或回滚事务
commit; #提交
rollback; #回滚
rollback to 回滚点名;
*/
事务的并发问题:
脏读:事务A访问数据时,读取到了事务B修改了但尚未提交的数据。(事务B没有提交,可能提交成功,但也有可能回滚)
不可重复读:事务A在访问数据时,由于事务B对数据进行了修改,使得事务A多次读取到的数据不一致。(违反了事务的一致性)
幻读:事务A读取数据时,事务B进行了插入或删除,导致第一个事务读取到了不同数目的数据。
如何避免事务的并发问题?(设置隔离级别)
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
read uncommitted(读未提交) | 可能发生 | 可能发生 | 可能发生 |
read committed(读已提交) | 不可能发生 | 可能发生 | 可能发生 |
repeatable read(可重复读) | 不可能发生 | 不可能发生 | 可能发生 |
serializable(串行化) | 不可能发生 | 不可能发生 | 不可能发生 |
设置隔离级别:
set session|global transaction isolation level 隔离级别名;
查看隔离级别:
select @@tx_isolation; #mysql默认的隔离级别是repeatable read(可重复读)