目录
内置函数
日期函数
字符串函数
数学函数
其他函数
复合查询(重点)
基本查询
多表查询
自连接
子查询
单行子查询
多列子查询
多列子查询
在from子句中使用子查询
合并查询(用得不多)
表的内连和外连(重点)
内连接
外连接
左外连接
右外连接
内置函数一般要用select调用
内置函数
日期函数
current_date函数
current_date函数用于获取当前的日期。如下:
current_time函数
current_time函数用于获取当前的时间。如下:
current_timestamp函数
获取时间戳,会给我们转化成日期+时间的格式显示
now函数
now函数用于获取当前的日期时间。如下:
date函数
date函数用于获取当前的日期时间。如下:
date_add函数
date_add函数用于在日期的基础上添加日期或时间。如下:
如果在date_add函数中添加的日期/时间为负值,则相当于在日期的基础上减去日期/时间。如下:
date_sub函数
date_sub函数用于在日期的基础上减去日期或时间。如下:
如果在date_sub函数中减去的日期/时间为负值,则相当于在日期的基础上添加日期/时间。如下:
datediff函数
datediff函数用于获取两个日期的差,单位是天。如下:
综合案例
创建一个评论表,表中包含自增长的主键id、昵称、评论内容和评论时间。如下:
向表中插入一些数据,插入时直接通过now函数指明评论时间。如下:
在显示评论信息时,如果只想显示评论的日期而不显示评论的时间,可以在查询sendtime字段时,通过date函数截取sendtime的日期部分进行显示。如下:
再不定时向表中插入一些数据。如下:
怎么才能在显示评论信息时,查询2分钟内发布的评论信息?
实际就是要筛选出评论时间加上2分钟后大于当前时间的评论,这时需要同时借助date_add和now函数。如下:
select * from msg where date_add(sendtime, interval 2 minute) > now();
字符串函数
charset函数
现有如下员工表,要求获取员工表中ename列使用的字符集。如下:
在查询员工表中的信息时,使用charset函数获取ename列使用的字符集即可。如下:
concat函数
现有如下成绩表,要求以“XXX的语文是XX分,数学是XX分,英语是XX分”的格式显示成绩表中的信息。如下:
在查询成绩表中的信息时,使用concat函数按要求进行字符串连接即可。如下:
instr函数
instr函数用于获取一个字符串在另一个字符串中首次出现的位置,如果没有出现则返回0。如下:
未找到的情况
ucase函数
ucase函数用于获取转换成大写后的字符串。如下:
lcase函数
lcase函数用于获取转换成小写后的字符串。如下:
left函数
left函数用于从字符串的左边开始,向后截取指定个数的字符。如下:
right函数
right函数用于从字符串的右边开始,向后截取指定个数的字符。如下:
length函数
length函数用于获取字符串占用的字节数。如下:
注意:length函数返回字符串长度,以字节为单位。如果是多字节字符则计算多个字节数;如果是单字 节字符则算作一个字节。比如:字母,数组算作一个字节,中文表示多个字节数(与字符集编码有关)
replace函数
replace函数用于将字符串中的指定子字符串替换成另一个字符串,例如将员工表中所有名字中的“S”替换成“上海”。如下:
strcmp函数
strcmp函数用于逐字符按照ASCII码比较两个字符串的大小,两个字符串大小相等返回0,前者大返回1,后者大返回-1。如下:
需要注意的是,strcmp函数在比较时是不区分大小写的。如下:
substring函数
substring函数用于从字符串的指定位置开始,向后截取指定个数的字符。如下:
使用substring函数时,如果没有指定要截取的字符个数,则默认从指定位置开始截取到最后。如下:
例如截取员工表中ename字段的第二个到第三个字符。如下:
ltrim、rtrim和trim函数
trim函数用于去除字符串的前后空格。ltrim和rtrim函数分别用于去除字符串的前空格和后空格。如下:
数学函数
abs函数
abs函数用于获取一个数的绝对值。如下:
bin函数
bin函数用于将一个十进制数转换成二进制。如下:
hex函数
hex函数用于将一个十进制数转换成十六进制。如下:
conv函数
conv函数用于将一个数从一个进制转换成另一个进制。如下:
ceiling函数
ceiling函数用于对一个数进行向上取整。如下:
需要注意的是,向上取整本质是向正无穷方向取整,因此负数向上取整后得到的是第一个大于等于该数的整数。如下:
4种取整方案:四舍五入(数学计算)、向上取整(银行)、向下取整(工龄)、零向取整(语言很常见)
floor函数
floor函数用于对一个数进行向下取整。如下:
需要注意的是,向下取整本质是向负无穷方向取整,因此负数向下取整后得到的是第一个小于等于该数的整数。如下:
format函数
format函数用于对数值进行格式化,以四舍五入的方式保留指定位数的小数。如下:
rand函数
rand函数用于生成0.0到1.0的随机浮点数。如下:
如果想要生成0到100的随机数,可以用生成的随机浮点数乘以100,然后再以某种取整方式进行取整。如下:
mod函数
mod函数用于对数值进行求余运算。如下:
其他函数
user函数
user函数用于获取MySQL连接的当前用户名和主机名。如下:
database函数
database()显示当前正在使用的数据库 如下:
md5函数
md5函数用于对一个字符串进行md5摘要,摘要后得到一个32位字符串。如下:
拓展:
- 一般情况下公司内部数据库不会存储用户的明文密码,而会将用户密码形成摘要后存储对应的摘要,当用户登录账号时,将用户输入的的密码形成摘要后与数据库中存储的摘要做对比,如果对比成功则允许登录。
- 这么做的好处主要有两个,第一个好处就是公司内部数据库中存储的不是用户的明文信息,就算用户信息泄露了也不会产生太大影响,第二个好处就是形成的摘要是定长的,这样有利于数据库表结构的设计。
password函数
password函数用于对用户数据进行加密。如下:
password函数输入之后。命令行不能被回滚到。这是mysql的一种保护机制
ifnull函数
ifnull函数接受两个参数,如果第一个参数不为null则返回第一个参数值,否则返回第二个参数值。类似语言上的三目操作符。如下:
复合查询(重点)
基本查询
准备测试表
- 下面给出三张表,分别是员工表(emp)、部门表(dept)和工资等级表(salgrade)。
- 后续所要进行的查询操作都将以这三张表作为数据源,包括基本查询和复合查询。
员工表(emp)中包含如下字段:
- 雇员编号(empno)。
- 雇员姓名(ename)。
- 雇员职位(job)。
- 雇员领导编号(mgr)。
- 雇佣时间(hiredate)。
- 工资月薪(sal)。
- 奖金(comm)。
- 部门编号(deptno)。
员工表(emp)中的内容如下:
部门表(dept)中包含如下字段:
- 部门编号(deptno)。
- 部门名称(dname)。
- 部门所在地点(loc)。
部门表(dept)中的内容如下:
工资等级表(salgrade)中包含如下字段:
- 等级(grade)。
- 此等级最低工资(losal)。
- 此等级最高工资(hisal)。
工资等级表(salgrade)中的内容如下:
其实复合查询就是把步骤拆分成单表查询的思想
查询工资高于500或岗位为MANAGER的员工,同时要求员工姓名的首字母为大写的J
我们先进行分解查询,先查询工资高于500或岗位为MANAGER的员工
然后再上面的条件下,用模糊搜索筛选出员工姓名的首字母为大写的J
按部门号升序而员工工资降序显示
在order by子句中依次指明按部门号排升序和按员工工资排降序,即不同部门的员工按照部门号排升序,而同一部门的员工按员工工资排降序。如下:
查询员工信息,按年薪降序显示
思路:1.需要员工信息,薪资*12+comm 2.对年薪进行降序排序
但是我们发现结果为什么会有NULL呢,难道我员工干了一年,最后年薪是NULL吗???
答案是因为有些员工的奖金部分是NULL,如果直接加上NULL就会出现这个情况
所以我们可以用ifnull来进行解决,判断一个员工是否有奖金吗,有的话就是对应的值,没有的话就是0
显示工资最高的员工的名字和工作岗位
解决该问题需要进行两次查询,先对员工表进行一次查询得到最高工资,然后再根据最高工资对员工表进行一次查询,得到工资等于最高工资的员工的姓名和岗位。如下:
此外,这种问题还可以使用子查询,将第一次查询的SQL语句用括号括起来,作为最高工资直接在第二次查询的SQL语句中使用。如下:
查询工资高于平均工资的员工信息
解决该问题也需要进行两次查询,先对员工表进行一次查询得到平均工资,然后再根据平均工资对员工表进行一次查询,筛选出工资高于平均工资的员工信息,该问题同样可以使用子查询。如下:
查询每个部门的平均工资和最高工资
在group by子句中指明按照部门号进行分组,在select语句中使用avg函数和max函数,分别查询每个部门的平均工资和最高工资。如下:
查询平均工资低于2000的部门号和它的平均工资
先group by聚合,然后进行筛选,再计算平均工资
注意,这里有两个易错点,容易写成下面两种模式
select deptno,sal 平均工资 from emp group by deptno where 平均工资< 2000;
- 使用了"sal"而不是"avg(sal)" - 这样不会计算平均值
- 使用了"WHERE"而不是"HAVING" - WHERE 子句不能用于聚合函数如 AVG(),而 HAVING 专门用于对聚合结果进行筛选
查询每种岗位的雇员总数和平均工资
在group by子句中指明按照岗位进行分组,在select语句中使用count函数和avg函数,分别查询每种岗位的雇员总数和平均工资。如下:
多表查询
实际开发中往往数据来自不同的表,所以需要多表查询。本节我们用一个简单的公司管理系统,有三张表EMP,DEPT,SALGRADE来演示如何进行多表查询。
- 在进行多表查询时,只需要将多张表的表名依次放到from子句之后,用逗号隔开即可,这时MySQL将会对给定的这多张表取笛卡尔积,作为多表查询的初始数据源。
- 多表查询的本质,就是对给定的多张表取笛卡尔积,然后在笛卡尔积中进行查询。
所谓的对多张表取笛卡尔积,就是得到这多张表的记录的 所有可能有序对组成的集合 ,比如下面对员工表和部门表进行多表查询,由于查询语句中没有指明筛选条件,因此最终得到的结果便是员工表和部门表的笛卡尔积。
说明一下:
- 员工表和部门表的笛卡尔积由两部分组成,前半部分是员工表的列信息,后半部分是部门表的列信息。
笛卡尔积的形成过程可以这样理解:
- 从员工表中取出第一条记录
- 将这条员工记录与部门表中的每一条记录组合,形成多个新记录
- 然后从员工表中取出第二条记录
- 重复步骤2,将第二条员工记录与部门表中的所有记录组合
- 依此类推,直到员工表中的所有记录都处理完毕
笛卡尔积的初步过滤
需要注意的是,对多张表取笛卡尔积后得到的数据并不都是有意义的,比如对员工表和部门表取笛卡尔积时,员工表中的每一个员工信息都会和部门表中的每一个部门信息进行组合,而实际一个员工只有和自己所在的部门信息进行组合才是有意义的,因此需要从笛卡尔积中筛选出员工的部门号和部门的编号相等记录。如下:
说明一下: 进行笛卡尔积的多张表中可能会存在相同的列名,这时在选中列名时需要通过表名.列名
的方式进行指明。
显示部门号为10的部门名、员工名和员工工资
由于部门名只有部门表中才有,而员工名和员工工资只有员工表中才有,因此需要同时使用员工表和部门表进行多表查询,在where子句中指明筛选条件为员工的部门号等于部门编号,并且部门号为10的记录。如下:
说明一下: 第一个筛选条件已经筛选出员工的部门号和部门编号相等的记录,因此在筛选部门号等于10的部门时,可以使用员工表中的部门号,也可以使用部门表中的部门编号。
显示各个员工的姓名、工资和工资级别
由于员工名和工资只有员工表中才有,而工资级别只有工资等级表中才有,因此需要同时使用员工表和工资等级表进行多表查询,在where子句中指明筛选条件为员工的工资在losal和hisal之间的记录。如下:
说明一下:
- 员工表和工资等级表的笛卡尔积中,将每一个员工的信息和每一个工资等级的信息都进行了组合,而实际一个员工只有和自己的工资对应的工资等级信息进行组合才是有意义的。
- 因此需要根据各个工资等级的最低工资和最高工资判断一个员工是否属于该工资等级,进而筛选出有意义的记录。
自连接
- 自连接是指在同一张表进行连接查询,也就是说我们不仅可以取不同表的笛卡尔积,也可以对同一张表取笛卡尔积。
- 如果一张表中的某个字段能够将表中的多条记录关联起来,那么就可以通过自连接将表中通过该字段关联的记录组合起来。
select * from emp,emp;
这种是错的。要对表起别名,比如这样
select * from emp e1,emp e2;
对同一张表做笛卡尔积
显示员工FORD的上级领导的编号和姓名
解决该问题可以使用子查询,先对员工表进行查询得到FORD的领导的编号,然后再根据领导的编号对员工表进行查询得到FORD领导的姓名。如下:
此外,解决该问题也可以使用自连接,因为员工表中的mgr字段能够将表中员工的信息和员工领导的信息关联起来。如下:
对员工表进行自连接后,在where子句中指明筛选条件为员工的领导编号等于领导的编号,这时就能筛选出每个员工信息与其领导信息组合形成的记录,进一步指明筛选条件为员工的姓名为FORD,这时便能筛选出员工FORD的信息和他的领导的信息组成的记录。如下:
子查询
- 子查询是指嵌入在其他SQL语句中的查询语句,也叫嵌套查询。
- 子查询可分为单行子查询、多行子查询、多列子查询,以及在from子句中使用的子查询。
单行子查询
单行子查询,是指返回单行单列数据的子查询。
显示SMITH同一部门的员工
在子查询中查询SMITH所在的部门号,在where子句中指明筛选条件为员工部门号等于子查询返回的部门号
多列子查询
单行子查询是指子查询只返回单列,单行数据;多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子 查询则是指查询返回多个列数据的子查询语句
in关键字:显示和10号部门的工作岗位相同的员工的名字、岗位、工资和部门号,但是不包含10号部门的员工
先查询10号部门有哪些工作岗位,在查询时最好对结果进行去重,因为10号部门的某些员工的工作岗位可能是相同的。如下:
然后将上述查询作为子查询,在查询员工表时在where子句中使用in关键字,判断员工的工作岗位是子查询得到的若干岗位中的一个,如果是则符合筛选条件,由于要求筛选出来的员工不包含10号部门的,因此还需要在where子句中指明筛选条件为部门号不等于10。如下:
all关键字;显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
先用基本的方法写
any关键字;显示工资比30号部门的任意员工的工资高的员工的姓名、工资和部门号,包含30号部门的员工
解决该题目也需要先查询30号部门员工的工资,然后在查询员工表时在where子句中使用any关键字,判断员工的工资是否高于子查询的得到的工资中的某一个,如果是则符合筛选条件。如下:
注意:不能拿一个列的属性,跟所有列的属性去比较
但实际这道题也等价于找到工资高于30号部门的最低工资的员工,因此也可以使用单行子查询得到30号部门的最低工资,然后判断员工的工资是否高于子查询得到的最低工资即可,由于要求筛选出来的员工包含30号部门的,因此不需要再对部门号进行过滤。如下:
多列子查询
多列子查询,是指返回多列数据的子查询。
查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人
查询思路:先查询SMITH属于哪个部门的,然后再用多列子查询,查询出来和SMITH的部门和岗位完全相同的所有雇员,最后再排除SMITH本人
mysql> select ename from EMP where (deptno, job)=
(select deptno, job from EMP where ename='SMITH') and ename <> 'SMITH';
也可以用 in 把 和SMITH的部门和岗位完全相同的所有雇员 看成一对
总结:目前全部的子查询,全部都在where子句中,充当判断条件。任何时刻,查询出来的临时结构,本质在逻辑上也是表结构。MySQL中一切皆表
在from子句中使用子查询
- 子查询语句不仅可以出现在where子句中,也可以出现在from子句中。
- 子查询语句出现from子句中,其查询结果将会被当作一个临时表使用。
显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资
思路过程:第一步:先查找所有部门的平均薪资,然后再分组查找每个部门的平均薪资,最后再把每个部门的平均薪资的结果充当个临时表,搭配from。注意要起别名
第二步:有些数据是没意义的,就好比SMITH是20号部门的,你给她个10号部门的平均薪资,是没有意义的,所以我们要用笛卡尔积给去除掉
最后在进行筛选大于平均工资的
附加条件:顺便显示在哪个地方工作
部门的工作地点是在dept中,所以是先用笛卡尔积,我们上面按照需要筛选出来的员工跟部门表进行合并,起个别名为t1
然后去掉无效信息
再按照所要求的信息。需要符合要求的员工名称,部门地点,部门
显示每个部门工资最高的人的姓名、工资、部门、最高工资
select EMP.ename, EMP.sal, EMP.deptno, ms from EMP,
(select max(sal) ms, deptno from EMP group by deptno) tmp where EMP.deptno=tmp.deptno and EMP.sal=tmp.ms;
肯定是先聚合,先把每个部门工资的薪资先找到
把这个结果作为临时表与emp表进行笛卡尔积组合
然后进行筛选去掉无效信息
最后按照要求
显示每个部门的信息(部门名,编号,地址)和人员数量
方法1:使用多表(不推荐,因为为了要照顾group by语法结构,还需要对多个数据进行分组)
select DEPT.dname, DEPT.deptno, DEPT.loc,count(*) '部门人数' from EMP, DEPT
where EMP.deptno=DEPT.deptno
group by DEPT.deptno,DEPT.dname,DEPT.loc;
过程:先统计每个部门有多少人,然后按照部门分组
然后进行笛卡尔积,把两个表放在一起,去除无效信息
最后再按照要求
方法2:使用子查询
先进行分组计算每个部门的人数,然后进行聚合
最后再按照要求
解决多表问题的本质:想办法将多表转换成单表,所以mysql中,所有select的问题全部都可以转换成单表问题(多表查询的指导思想)
合并查询(用得不多)
在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all
- union用于取得两个查询结果的并集,union会自动去掉结果集中的重复行。
- union all也用于取得两个查询结果的并集,但union all不会去掉结果集中的重复行。
union
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。
将工资大于2500或职位是MANAGER的人找出来
mysql> select ename, sal, job from EMP where sal>2500 union -> select ename, sal, job from EMP where job='MANAGER';//去掉了重复记录
步骤如下,union会帮你去重
union all
该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。
案例:将工资大于25000或职位是MANAGER的人找出来
mysql> select ename, sal, job from EMP where sal>2500 union all -> select ename, sal, job from EMP where job='MANAGER';
注意:两个select的列信息和属性必须一样!!!
表的内连和外连(重点)
表的连接分为内连和外连
内连接
内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。
内连接的SQL如下:
select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件;
说明一下:
- SQL中大写的表示关键字,[ ]中代表的是可选项。
- 内连接的条件通过
连接条件
指明,用户的其他筛选条件通过其他条件
指明。
显示SMITH的名字和部门名称
给出一张员工表和一张部门表,员工表中的ename代表的是员工的姓名,deptno代表的是员工所在部门的部门号。如下:
现在要显示SMITH的名字和其所在部门的名称,按照复合查询的做法就是,取员工表和部门表的笛卡尔积,在where子句中指明筛选条件为员工的部门号等于部门的部门号,筛选出每个员工匹配的部门信息,并指明员工姓名为SMITH,筛选出SMITH的信息和其所在部门的信息。如下:
实际上述多表查询的方式本质就是内连接,用标准的内连接SQL编写:
- 将员工表和部门号放在from子句中并通过inner join关键字隔开。其实是等于笛卡尔的那种写法
- 在on子句后指明内连接的条件为员工的部门号等于部门的部门号,保证筛选出来的数据是有意义的。
- 在and之后指明筛选条件为员工的姓名为SMITH。
//用标准的内连接写法
select ename, dname from EMP inner join DEPT on EMP.deptno=DEPT.deptno and
ename='SMITH';
这样筛选出来的结果和多表查询筛选出来的结果是一样的,只不过是写法更直观而已。如下:
外连接
外连接分为左外连接和右外连接。
左外连接
如果联合查询,左侧的表完全显示我们就说是左外连接。 (以左侧表为主进行拼接)
语法:
select 字段名 from 表名1 left join 表名2 on 连接条件
查询所有学生的成绩,如果这个学生没有成绩,也要将学生的个人信息显示出来
给出一张学生表和一张成绩表,学生表中的name代表的是学生的姓名,id代表的是学生的学号。如下:
成绩表中的id代表的是考试学生的学号,score代表的是学生的成绩。如下:
现在要显示所有学生的成绩,如果直接使用内连接将学生表和成绩表连接起来,然后筛选出学生学号等于考试学生学号的记录,那么只能筛选出有考试成绩的学生信息。如下:
而题目要求将没有成绩的学生的个人信息也要显示出来,也就是学生表当中的内容需要完全被显示出来。如果在连接学生表和成绩表时将学生表放在左侧,那么就可以使用左外连接,这时如果左侧表中的某条记录根据连接条件没有找到匹配的右侧表中的记录,就会直接显示左侧表中的记录信息,而其对应的右侧表中的列信息将会用NULL值进行填充。如下:
右外连接
如果联合查询,右侧的表完全显示我们就说是右外连接。
语法:
select 字段 from 表名1 right join 表名2 on 连接条件;
查询所有的成绩,就算这个成绩没有学生与它对应,也要将成绩信息显示出来
题目要求将没有学生与它对应的成绩信息也要显示出来,也就是成绩表当中的内容需要完全被显示出来。如果在连接学生表和成绩表时将成绩表放在右侧,那么就可以使用右外连接,这时如果右侧表中的某条记录根据连接条件没有找到匹配的左侧表中的记录,就会直接显示右侧表中的记录信息,而其对应的左侧表中的信息将会用NULL值进行填充。如下:
列出部门名称和这些部门的员工信息,同时列出没有员工的部门
由于题目要求同时列出部门名和员工信息,因此需要将部门表和员工表连接起来,连接条件就是部门的部门号要等于员工所在的部门号。如果直接使用内连接进行查询,那么将会显示出所有满足连接条件的记录。如下:
而题目要求同时列出没有员工的部门,也就是部门表当中的内容需要完全被显示出来,如果在连接部门表和员工表时将部门表放在左侧,那么就可以使用左外连接。如下:
当然,如果要使用右外连接,那么可以在连接部门表和员工表时将部门表放在右侧。如下: