查询是sql语句中非常重要的一部分,写的sql语句大部分需要围绕着select展开。
查询语句中可以包含这些功能:这些功能的关键字在select语句中出现的顺序颠倒
下面是几个表,这里按照这几个表来进行查询
基础查询此次除涉及到:基础查询语句、为数据表起别名、对字符串进行拼接的函数、查询当前MySQL版本的函数、SQL语句中使用运算符、去重还有基础的查询条件(where)
当多个表之间相互连接着查询,为了分辨,则一般需要给表起别名
select `gradeid` as 年级ID,`gradename` as 年级名称 from `grade`;
-- as用于为表或字段起别名
-- 此处,as后面跟着的字符串,是为此字段起的一个别名。
-- 我们可以通过为字段起别名的方式,在结果中用不同的结果来替代原字段名
-- 等同于:select `gradeid` 年级ID,`gradename` 年级名称 from `grade`;
三个基础知识
select concat('ID:',gradeid) 年级ID ,concat('名称:',`gradename`) 年纪名称 from `grade`;
-- 上面用到了一个函数:concat(参数列表),此函数需要传入字符串形式的参数。参数可为变量
-- 此函数的作用是将多个字符串进行拼接
-- 在此处的作用是在查询到的数据前加上说明
-- 查询当前MySQL版本号
select version();
-- 在MySQL查询语句中也可以使用运算符:
select 12*15+999;
select `studentresult`+5 from `result`; #此处将查询出的结果加5
去重可以根据某个字段来去重。根据某个字段的值,去掉重复的记录
-- 去重
select distinct `subjectname` from `subject`;
-- 在select后面加上distinct,则此查询,会根据distinct后面跟着的字段来判断是否重复,然后去重
基础查询条件(where):
查询条件用于过滤筛选,从而得到我们想要的记录,需要用到where和各种查询符号
-- 在修改中,要先查询到记录,那里面的查询条件和方式在这里当然也可以使用
-- 查询条件:在查询条件中可以使用操作符(<,>,<=,>=,!=(等同于<>),=)
-- 还有三个特殊一点的between...and...(在两者之间,如between 1 and 3 表示[1,3]是一个闭区间)
-- or(||) 或运算符 and(&&) 与运算符 not(!)非
-- 这些符号可以综合使用之间
-- -- 判断某个字段是否为某一个状态用is,不要用= 比如在判断某条记录的某个字段值是否为空的时候
select * from `subject`
where `subjectno`>16;
所谓的模糊查询,其实就是在查询的过滤条件上做文章,比如判断记录的某个字段是否符合条件,条件是对应的字段必须含有某个值,如:查询学生中姓李的同学,或名字中有大的同学… …。对此我们一般需要使用这些关键字或字符(like+in+_+%)。
-- ==================================模糊查询===================================
-- like,用于模糊查询。一般和'_'或'%'组合起来使用
select `gradename` FROM `grade`
where `gradename` like '%大%';
-- '%'这个符号表示任意个字符。
-- 此处的语句意思:查找grade表中的grade字段,如果此字段对应的数据中有'大'这个字符,则返回这些记录中的gradename字段
select * from `grade`
where `gradename` like '_三';
-- '_'表示一个字符
-- 此处的意思:查找`grade`表的`gradename`字段,如果此字段对应的数据为两个字符,且最后一个字符为'大',则返回对应的记录
-- 关键字in,当字段数据和in后面括号中的任意一个数据匹配,则返回这些记录
select * from `grade`
where `gradename` in('大一','预科班','大三');
所谓连接查询,就是联合多个表进行查询。比如,一个成绩表,一个学生表,我们需要查询每个成绩记录中的所有信息和对应的学生信息。而连接两个表的关键在于找到两表中相同的部分,如此处,每个成绩记录中有一个字段记录的是对应参加考试的学生的学号,则我们可以通过成绩表中的学号和学生表中的学号来进行连表查询
连表查询最基础的有三种:left join(左查询),inner join(并集查询),right join(右查询)
left join就是显示左边的所有数据,及右边表中和左边有交集部分的数据,inner join只显示有交集的行
至于right与left可以看作是以谁为主
-- ============语法=============
-- select 要查询的记录中的字段名
-- from 表1
-- right join或left join或inner join 表2
-- on 条件判断;
inner join(并集查询),查询结果仅返回两表中都有的那些记录,即返回两表交集的记录
下面查询参加考试的学生姓名,考号,参考课程,考试成绩
-- ============================inner join 返回两表交集的记录==================================
select s.studentno,studentname,subjectno,studentresult
-- 查询指定字段,且此字段是两表都有的,则需要在这里加上一个标识,此处即s.student,表示此处返回的是s表的studentno字段
from student s # 为表起别名
inner join result r
on s.studentno=r.studentno;-- where s.studentno=r.studentno; 把on替换成where也可以
-- 返回的每条记录显示的不一定是全部的字段,仅仅显示对应的查询的字段。
-- 当然可以用*来返回两表记录中所有的字段
left join就是显示左边的所有数据,及右边显示的是和左边有交集部分的数据,inner join只显示有交集的行
至于right与left可以看作是以谁为主
where条件:在生成临时表基础上,再加条件限制。
下面查询所有的考生
-- ================left join 返回左边表的全部记录和两表的交集记录====================
select s.studentno,studentname,subjectno,studentresult
from student s
left join result r
on s.studentno=r.studentno;
右查询和左查询的区别就在于以哪个表为主,其实左右查询两者没多大差别,用哪个都行,无非是把right join或left join两边的表交换一下
-- ==================right join 返回右边表的所有记录和两表交集============================
select s.studentno,studentname,subjectno,studentresult
from student s
right join result r
on s.studentno=r.studentno;
查询没考试的所有学生信息
-- ======================查询没有考试的学生的全部信息==========================================
select *
from student s
left join result r
on s.studentno=r.studentno
where subjectno is null;
-- 判断某个字段是否为某一个状态用is,不要用=
连接查询理论上可以连接超级多的表进行查询。比如我们需要同时查询某学生的基本信息、考试信息、考试科目的所有信息,此时需要连接三个表(student、result、subject ),我们此时仅需要做的是先连接两个表,再在此基础上连接第三个表
-- ==========================两表以上的连表查询================================================
-- 三表查询
select s.studentno,r.subjectno,subjectname,studentresult
from student s
right join result r
on s.studentno=r.studentno
inner join subject sub
on r.subjectno=sub.subjectno
where studentname = '张伟';
-- select后面跟的字段名仅仅是作为查询出的结果的参照,并不影响后面的判断条件。
-- 简单来说,后面的查询或连接条件中使用的字段名,可以不在select后面的字段名列表里
-- 如当仅查询参加考试的学生姓名,则在select后面字段名处仅写`studentname`即可。
-- 后面on或where中还可以直接使用studentno,等一些未在select后面出现的字段名
在连接查询的基础上我们可以再加where过滤条件,如上
语法:
-- =========语法=========
-- select 要查询的记录中的字段名
-- from 表1
-- right join或left join或inner join 表2
-- on 条件判断
-- right join或left join或inner join 表3
-- on 条件判断
-- .........以此类推,表1,2,3,....,n
子查询就是嵌套查询,即一个查询条件中嵌套另一个查询条件。比如查询参加考试,且成绩大于80,且上牛蛙2课的学生姓名,学号。用子查询需要在课程表中先查询出牛蛙2课的课程编号是多少,然后根据这些查询出的编号,在成绩表中来查询筛选出参加考试,且成绩大于80的学生的学号,然后根据这些学号在学生表中查询出学生姓名。
此处需要三个表的嵌套子查询,如下
-- ===============================子查询===================================
-- 子查询就是嵌套查询,即一个查询条件中嵌套另一个查询条件,一般可无限套娃
-- 他的作用和连接查询类似,同于多个表间的条件查询
-- 用子查询查询出参加考试,且成绩大于80,且上牛蛙2课的学生姓名,学号
select `studentname`,`studentno` from `student` where `studentno` in(
select `studentno` from `result` where `studentresult`>80 and `subjectno`=(
select `subjectno` from `subject` where `subjectname`='牛蛙2'
)
);
连接查询只会遍历一次,子查询可能会对多个表进行遍历,但是数据量少的话也就无所谓是连接查询还是子查询,多表数据量大建议采用连接查询。
自连接查询其实是一种特殊的连接查询,一般的连接查询是两个不同的表进行连接查询,而自连接查询是两个一模一样的表进行连接查询,其实就是一个表,复制一份,两者进行连接查询
如下,一个表(category)
表中有着一个父子从属关系,每条记录有两个表示id的字段,一个表示自身的id(categoryid),另一个表示自身父辈的id(pid)
下面,我们查询出所有的父辈的categoryname值和子辈的categoryname值
-- ===================================自连接查询===========================================
-- 也是一种连接查询,一般的链接查询是两个不同表之间的连接,然后查询,
-- 自连接查询是两个相同的表进行连接查询。
-- 简单来说,就好比是把一个表复制一份,现在有了两个一样的表,然后把这两个表连接起来进行查询
-- 这里有一个表(category),表中各个记录之间有着父子关系。
-- 每条记录有两个表示id的字段,一个表示自身的id(categoryid),另一个表示自身父辈的id(pid)
-- 下面我们想查询出表中所有的父子关系的categoryname值
select a.`categoryname` as '父栏目',b.`categoryname` as '子栏目'
#我们想要的结果是一边是父类的名称,另一半是子类的名称,所以这里需要把categoryname写两次。
-- 为了方便分辨父categoryname值和子categoryname值,这里把字段前面加上各自的表的标识,并为其起别名
from `category` as a,`category` as b #这里把同一个表进行两次查询,就类似于把一个表复制了一份。
#为了方便分辨哪个当做父类哪个当做子类来查询,这里为两个表设置不同的别名
where a.categoryid=b.pid; #这里设置查询条件,即,记录引用的id=记录的id
排序属于我们的常用操作,一般写在业务层,也可写在sql语句中,此处记录一个在sql语句中的排序方法。为了程序的性能我们还需要在sql语句中进行分页,分页需要在持久层进行实现才可以有效的提高程序性能。
此处一个对查询出的结果进行排序的一种方法,可根据指定字段进行排序
-- =================================排序查询==============================
-- 通过sql语句对查询出的结果进行排序
-- 使用order by关键字和DESC和ASC关键字,DESC表示降序排列,ASC表示升序排列
-- 排序语句写在分页前,其他语句后
-- 链接三表查询出学生姓名,学号,考试科目,考试科目编号,考试成绩,并根据考试成绩排序
select s.studentno,studentname,r.subjectno,subjectname,studentresult
from student s
right join result r
on s.studentno=r.studentno
inner join subject sub
on r.subjectno=sub.subjectno
order by studentresult desc;
此处记录的仅仅是一个简单分页,仅可选择每页每页的容量和当前页从第几条记录开始显示
-- ==================================分页===================================
-- 通过limit关键字实现分页,他需要两个整形的参数。
-- limit n,m; n表示此页从表中的第几条记录开始,第一条记录对应的n为0。m表示此页容量是几条记录
-- n可以用(a-1)m替代,a表示当前是第几页
-- 连接三表查询出学生姓名,学号,考试科目,考试科目编号,考试成绩,根据考试成绩排序并实现分页
select s.`studentno`,studentname,r.subjectno,subjectname,studentresult
from `student` s
right join result r
on s.studentno=r.`studentno`
inner join subject sub
on r.subjectno=sub.subjectno
order by studentresult desc
limit 0,3; #表示从表中的第一条记录开始,此页最多容纳三条记录
sql语句中也会有一些函数,可以帮助我们快速的实现目标
ABS()
取绝对值。ceiling()
如果接受的值是一个浮点数,则向上取整。floor()
向下取整。rand()
返回一个0~1之间的随机数。sign()
判断数值正负(0,0。负数,-1。正数,1)。这几个函数都需要传入数值类型的参数current_date()
和now()
获取当前时间。curdate()
获取当前日期。localtime()
本地时间。sysdate()
系统时间。year(now())
,当前时间的年… … …SYSTEM_USER()
和user()
表示当前用户。version()
当前MySQL版本统计当前字段或表有几条记录count()
count(字段名)
,用于统计当前字段有几条数据,不包括null
count(*)
,统计全表有几条记
count(1)
,统计全表有几条记录
俩功能一样,但建议使用count(1)
,如果字段是主键,则使用count(主键)
,此时这样统计总行效率更高
下面函数需要传入字段名
sum()
,求和
avg()
,求平均值
max()
,求最大值
min()
,求最小值
这几个函数使用起来可能会有一些问题:
如下,把当前查询到的全部记录当做一组(查询语句,不使用分组,则默认查询到的所有数据为一组),求此组的平均值,每组只会有一个平均值,但是subjectname的值可能有多个,系统不知道展示哪个subjectname的值,就会出现subjectname此列的值不明确
原因:
MySQL5.7之后,sql_mode中ONLY_FULL_GROUP_BY模式默认设置为打开状态。ONLY_FULL_GROUP_BY的语义就是确定select target list中的所有列的值都是明确语义
简单的说来,在此模式下,target list中的值要么是来自于聚合函数(sum、avg、max等)的结果,要么是来自于group by list中的表达式的值。
解决方法:使用any_value()
函数
MySQL提供了any_value()函数来抑制ONLY_FULL_GROUP_BY值被拒绝,any_value()会选择被分到同一组的数据里第一条数据的指定列值作为返回数据
一个表中的所有记录可以根据某些条件进行分组,如可以把某个字段值一样的所有记录分为一组。
在一个select语句中,where只能出现一次,如果在某些情况下还需要进行过滤筛选,则可以使用having关键字
-- ===================================分组和having过滤=======================================
-- group by用于分租,指定结果按照哪个字段来分组,此列中,数据相同的分为一组。
-- 查询语句,不使用分组,则默认查询到的所有数据为一组
select any_value(`subjectname`),avg(`studentresult`) 平均分
from `result` r
inner join `subject` sub
on r.subjectno=sub.subjectno
group by subjectname
having 平均分>80;
-- having作用和wwhere一样,用于过滤。
-- 区别在于having可以写多个,where只能写一个
-- 且having在select语句中的顺序在分组后面,where在分组前面
在数据表中存储一些重要的东西,比如密码,我们直接把密码进行明文存储在数据表中是不安全的,所我们可以进行加密
MD5是一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。他的特点是不可逆。
我们使用可以使用MD5函数进行加密,MD5(要被加密的内容),此函数会根据传入的内容来返回一个16字节的序列值,此值是唯一的,传入的内容不同,返回的序列值则不同,此序列值不可逆,如果要判断一个新的内容是否与一个被加密的内容相同,则需要把新的内容也进行MD5加密,然后用此次生成的序列值对比另一个序列值,来判断两个内容是否相同
-- ================================================MD5加密==========================================================
-- 对于需要加密的内容,可以通过MD5进行加密
-- MD5是一种被广泛使用的密码散列函数,
-- 可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。他的特点是不可逆。
-- 我们使用MD5函数进行加密,MD5(要被加密的内容),
-- 此函数会根据传入的内容来返回一个16字节的序列值,此值是唯一的,传入的内容不同,返回的序列值则不同,此序列值不可逆,
-- 如果要判断一个新的内容是否与一个被加密的内容相同,则需要把新的内容也进行MD5加密,然后用此次生成的序列值对比另一个序列值,来判断两个内容是否相同
-- 创建一个表
create table `testMD5`(
`id` int not null auto_increment comment 'ID',
`name` varchar(30) comment '账号',
`password` varchar(30) comment '密码',
primary key(`id`)
)engine=innodb charset=utf8;
-- 插入一条数据
insert into `testMd5`(`name`,`password`) values('牛蛙二号','李哥哥');
-- 对数据进行加密
update `testMD5` set `password`= MD5('李哥哥') where `name`='牛蛙二号';
-- 或者直接在插入的时候进行加密
insert into `testMD5`(`name`,`password`) values('牛蛙三号',MD5('李哥哥'));
-- 比对密码
select * from `testMD5` where `password`=MD5('李哥哥');