MySQL 函数的使用解析及SQL连接查询


一、函数的作用


1.隐藏了实现细节
2.提高了代码的重用性和间接性

调用(可以嵌套):
select 函数名(实参列表) 【from 表】;

select 函数() from dual; 标准语法,dual是一个通用表,默认的调用函数都走这个表,默认可以省略成select 函数();

1.函数部分基础使用

select version();
select database();
select user();
select @@port;
select @@datadir;
select @@socket;


二、函数的分类:



1.单行函数
如 concat length ifnull 等
2.分组函数(组函数)
功能:做统计使用,又称为统计函数、聚合函数

1.单行函数


1.)字符函数

# length 获取参数值的字节个数
select length('john');    结果4
select length('张三丰hahaha');  结果15(utf8字符集下中文为3个字节)

# concat 拼接字符串
mysql> select concat('a','_','b') 姓名;
+--------+
| 姓名   |
+--------+
| a_b    |
+--------+
1 row in set (0.02 sec)

# upper lower 改变大小写
select upper('john') 结果 
union all 
select lower('JOHN');
+--------+
| 结果   |
+--------+
| JOHN   |
| john   |
+--------+
2 rows in set (0.00 sec)

# substr substring 字符截取
'注意:索引从1开始计数,截取的是字符长度而不是字节长度'
截取从指定索引处后的所有字符:
select substr('李莫愁爱上了陆展元',7) 输出;
+-----------+
| 输出      |
+-----------+
| 陆展元    |
+-----------+
1 row in set (0.01 sec)
截取从指定索引处后的指定个数字符:
select substr('李莫愁爱上了陆展元',1,3) 输出;
+-----------+
| 输出      |
+-----------+
| 李莫愁    |
+-----------+
1 row in set (0.00 sec)

# instr 返回子串第一次出现的索引位置,如果没有则返回0
select instr('abcXdefgx','x') as 输出;
+--------+
| 输出   |
+--------+
|      4 |
+--------+

"不区分大小写,支持中文字符查找。"

select instr('你好今日世界','今日') as 输出;
+--------+
| 输出   |
+--------+
|      3 |
+--------+

# trim 去前后空格或指定字符串(在中间的不会去除)
select trim('  ab c   ') as 输出;
+--------+
| 输出   |
+--------+
| ab c   |
+--------+

用'字符' from 方式指定字符
mysql> select trim('x' from 'xbcx  ax xxbcxx xaxxx') as 输出;
+-------------------+
| 输出              |
+-------------------+
| bcx  ax xxbcxx xa |
+-------------------+

select trim('x' from 'xxx  ax xxbcxx xxxx') as 输出;
+--------------+
| 输出         |
+--------------+
|   ax xxbcxx  |
+--------------+
'注意只去前后。其中有任意字符隔开后就变成了中间部分的内容而不会被去除了。'

# lpad 用指定的字符实现左填充至指定的总长度(rpad右填充)
select lpad('aaa',5,'*') 输出;
+--------+
| 输出   |
+--------+
| **aaa  |
+--------+
'如果长度不足则会截取长度。'
select lpad('aaaa',2,'*') 输出;
+--------+
| 输出   |
+--------+
| aa     |
+--------+

# replace 替换
select replace('abcd_aaa_bbb','aaa','xxx') as output;
+--------------+
| output       |
+--------------+
| abcd_xxx_bbb |
+--------------+
#替换是区分大小写的,需要注意。



2.)数学函数

#rand获取随机数,返回0-1之间的任意小数.
select rand();
+--------------------+
| rand()             |
+--------------------+
| 0.3116143292855605 |
+--------------------+

# round 四舍五入
select round(-1.55) output;   结果-2
select round(-1.567,2) output;  结果-1.57
select round(1567,-2) output;
+--------+
| output |
+--------+
|   1600 |
+--------+

# ceil 向上取整,返回>=该参数的最小整数
select ceil(1.002);   结果2
select ceil(-1.002);   结果-1

# floor 向下取整,返回<=该参数的最大整数
select floor(-9.99);   结果-10

# truncate 截断
select truncate(1.6999,1);  结果1.6
select truncate(16999,-2);
+--------------------+
| truncate(16999,-2) |
+--------------------+
|              16900 |
+--------------------+

# mod 取余数
select mod(10,3);  结果1
select 10%3;   结果1
select mod(-10,-3);  结果-1
select mod(10,-3);   结果1
'实际计算公式为':
mod(a,b) = a-a/b*b


3.)日期函数

# now返回当前系统时间
select now();

# curdate 返回当前系统日期,不包含时间。
select curdate();
+------------+
| curdate()  |
+------------+
| 2020-08-12 |
+------------+

# curtime 返回当前系统时间,不含日期。
select curtime();
#但是值本身包含完整时间.例如:
mysql> select year(curtime());
+-----------------+
| year(curtime()) |
+-----------------+
|            2020 |
+-----------------+

# 获取指定的年月日时分秒
select year('1981-1-1') 年;   结果 1981
select month('1981-1-1') 月;   结果 1
select monthname('1981-1-1') 月;  #结果 January
select day('1981-1-1');
select hour(now());
select minute(now());
select second(now());

# date_format 将日期转换为字符
select date_format(now(),'%Y年=%m月=%d日') output;
+-------------------+
| output            |
+-------------------+
| 2020年=08月=12日   |
+-------------------+
使用场景:常用于日期格式的转换
select date_format(now(),'%m月/%d日 %Y年') output;
+---------------------+
| output              |
+---------------------+
| 08月/12日 2020年    |
+---------------------+

# str_to_date 将字符通过格式转换成日期
查找日期为1992-04-03的所有信息
select * from 表 where 日期 = str_to_date('4-3 1992','%c-%d %y');
场景:一般情况下用于接受web端输入的日期信息(一般为str字符串类型)。
#注意:'%c-%d %y'不代表最后输出的日期格式,只是用对应的方法去解析日期。

附实例和时间函数表:



4.)其他函数

select version();
select database();
select user();
select password('字符') 返回一个字符对应的加密结果.
select md5('字符') 返回一个字符对应的md5加密结果.

select password('555');
+-------------------------------------------+
| password('555')                           |
+-------------------------------------------+
| *1D096071E42D900FF3B77C6AB23CBBBD6E4F3824 |
+-------------------------------------------+


5.)流程控制函数

# if 函数 判断输出
select if(10<5,'大','小') 比大小;
+-----------+
| 比大小    |
+-----------+
| 小        |
+-----------+
结果为是返回第一个值,结果为否返回第二个值

# case 多条件判断输出 使用1(等值判断)
语法:
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1
when 常量2 then 要显示的值2或语句2
....
else 要显示的值n或语句n;
end

# 注意case前要加,
举例1:
select 工资,部门编号,
case 部门编号
when 30 then 工资*1.5
when 40 then 工资*1.6
when 50 then 工资*1.7
else 工资 
end as 新工资
from 表;

使用world.city表例2:
mysql> select id,name,
    -> case id 
    -> when 1 then concat(name,'aa') 
    -> when 2 then concat(name,'bb') 
    -> else name
    -> end as 新名字
    -> from city limit 4;
+----+----------------+----------------+
| id | name           | 新名字         |
+----+----------------+----------------+
|  1 | Kabul          | Kabulaa        |
|  2 | Qandahar       | Qandaharbb     |
|  3 | Herat          | Herat          |
|  4 | Mazar-e-Sharif | Mazar-e-Sharif |
+----+----------------+----------------+
4 rows in set (0.00 sec)

# case 多条件判断输出 使用2(区间判断)
语法:
case 
when 条件1 then 要显示的值1或语句1
when 条件2 then 要显示的值2或语句2
....
else 要显示的值n或语句n
end

使用world.city表举例2:
mysql> select id,name,
    -> case
    -> when population>600000 then 'A级'
    -> when population>300000 then 'B级'
    -> when population>100000 then 'C级'
    -> else 'D级'
    -> end as 城市级别
    -> from city limit 10;
+----+---------------------+--------------+
| id | name                | 城市级别     |
+----+---------------------+--------------+
|  1 | Kabul               | A级          |
|  2 | Qandahar            | C级          |
|  3 | Herat               | C级          |
|  4 | Mazar-e-Sharif      | C级          |
|  5 | Amsterdam           | A级          |
|  6 | Utre                | B级          |
|  7 | Haagddd             | B级          |
|  8 | Utrecht             | C级          |
|  9 | Eindhoven           | C级          |
| 10 | Rotterdam           | A级          |
+----+---------------------+--------------+
# case条件相当于ifelse,会自动分割区间.不会产生重复覆盖的情况.


2.分组函数

1.基础函数

#以下函数运算的时候是忽略null值
sum()     求和
avg()     求平均值
min()     求最小值
max()     求最大值
count()   求非空值的个数(不为null)
count(*)  统计总行数
count(1)  统计总行数 ()中可以加任意常量,意义为在表的列中加多了一列全都为该常量.然后统计该常量的个数,即为表的总行数.

datediff('2017-10-1','2017-11-5') 日期差距天数,(前者减去后者)
mysql> select datediff('2017-10-1','2017-11-5');
+-----------------------------------+
| datediff('2017-10-1','2017-11-5') |
+-----------------------------------+
|                               -35 |
+-----------------------------------+

#参数支持的类型
max min支持字符型和日期型
count 支持任意类型.

2.分组查询

#语法:
select 分组函数,列(要求出现在group by的后面)
from 表
[where 筛选条件]
group by 分组的列表
[order by 子句]
[having子句];
'where条件需在from后和group by前.'
'除了where子句,其他子句都支持使用别名.'

例:
# 1.简单分组查询
查询每个工种的最高工资
select max(工资),工种id
from 工资表
group by 工种id;

# 2.多条件分组查询
查询邮箱中包含a字符的每个部门的平均工资
select avg(工资),部门id
from 工资表
where 邮箱 like '%a%'
group by 部门id;

# 3.多重分组查询
查询每个部门每个工种的员工平均工资
select avg(工资),部门id,工种id
from 工资表
group by 工种id,部门id;

# 4.添加排序
查询每个部门每个工种每个员工的平均工资,并按平均工资排序.
select avg(工资) aaa,部门id,工种id
from 工资表
group by 工种id,部门id
order by aaa desc;

#4.查询哪个部门的员工个数大于2
select count(*),部门id
from 工资表
group by 部门id
having count(*)>2;

#having函数用于筛选以上select语句的结果.

三、连接查询(多表查询)

当查询的字段来源于多个表时,用到连接查询
笛卡尔乘积现象:表1 m行,表2 n行,查询表1和表2,结果=m*n行 (原因:没有有效的连接条件)

分类标准:
sql192标准 :仅支持内连接
sql199标准 (推荐):mysql支持内连接+外连接(左外右外)+交叉连接(不支持全外连接)

#区别:
sql199支持的功能更多,可读性更高,实现连接条件和筛选条件的分离.


#按功能分类:
   内连接:
       等值连接
       非等值连接
       自连接
   外连接
       左外连接
       右外连接
       全外连接
   交叉连接

1.sql192标准

#1.等值连接
1) 多表等值连接的结果为多表的交集部分
2) n表连接,至少需要n-1个连接条件
3) 多表的顺序没有要求
4) 一般需要为表起别名
5) 可以搭配所有的子句使用,比如排序.分组.筛选

1例:查询女表中对应的男友名
select name女,name男
from 女表,男表
where 女表.男友id=男表.id
注意:"此查询结果与左外连接不同,如果女表查询结果有空值无对应的情况则会不显示."

#2.为表起别名
select * from 表名 as 别名(as可以省略)
例:
select a.id,b.id
from 表1 a,表2 b
where a.id=b.id;

!'如果为表起了别名,则查询的字段就不能使用原来的表名去查询了.'
例:
select 表1.id,表2.id
from 表1 a,表2 b
where a.id=b.id;
会执行报错,语句会先执行from后的表重命名然后再走select查询,导致表名不识别.

#3.三表连接查询
select name,部门name,city
from 表1 a,表2 b,表3 c
where a.部门name=b.部门名
and b.城市id=c.城市id

#4.非等值连接
例:查询员工的工资和工资级别
select name,工资,工资级别
from 工资表 a,工资等级表 b
where a.工资 between b.最低工资 and b.最高工资;

#5.自连接(内连接)
例如:查询员工名和上级领导的名字
+------+------+------+
| id   | name | lid  |
+------+------+------+
|    1 | fa   | NULL |
|    2 | fb   |    1 |
|    3 | fc   |    1 |
+------+------+------+
在同一张表中两次或多次查询.
mysql> select id,name,lid from bbb where id=lid;
Empty set (0.00 sec)
'结果为空,不是我们想要的结果.'

实际情况:第一次查询得到fb领导为1,1再次查询对应到fa
所以需要用到别名:
select a.id,a.name,b.name lname
from bbb a,bbb b
where a.lid=b.id;
+------+------+-------+
| id   | name | lname |
+------+------+-------+
|    2 | fb   | fa    |
|    3 | fc   | fa    |
+------+------+-------+

2.sql199语法

# 1.等值连接inner join (inner是可以省略不写)
# .两表连接
查询员工名,部门名
select name,部门名
from 员工表 a
inner join 部门表 b
on a.部门id=b.部门id

# .两表连接多子句
两表连接查询每个部门的员工个数>3的部门名和员工个数,并按个数降序
select count(*),部门名
from 员工表 a
inner join 部门表 b
on a.部门id=b.部门id
group by 部门名
having count(*)>3
order by count(*) desc;

# .三表连接使用2个inner join
三表连接查询员工名,部门名,工种名,并按部门名降序
select name,部门名,工种名
from 员工表 a
inner join 部门表 b on a.部门id=b.部门id
inner join 工种表 c on a.工种id=c.工种id
order by 部门名 desc;

# 2.非等值连接
例:查询员工的工资和工资级别的个数>20,并按工资级别降序
select name,工资,工资级别
from 工资表 a
join 工资等级表 b
on a.工资 between b.最低工资 and b.最高工资
group by 工资级别
having count(*)>20 
order by 工资级别 desc;

# 3.内连接
例如:查询员工名和上级领导的名字
+------+------+------+
| id   | name | lid  |
+------+------+------+
|    1 | fa   | NULL |
|    2 | fb   |    1 |
|    3 | fc   |    1 |
+------+------+------+
select a.id,a.name,b.name lname
from bbb a
inner join bbb b
on a.lid=b.id;
+------+------+-------+
| id   | name | lname |
+------+------+-------+
|    2 | fb   | fa    |
|    3 | fc   | fa    |
+------+------+-------+

# 4.外连接
场景:常用于查询一个表中有另一个表中没有的数据.
'分主表和从表,查询结果为主表所有记录,以主表数据去从表中查找,没有结果的部分返回null'
1)left outer join左外连接,left左边的是主表
2)right outer join右外连接,right右边的是主表

例如:查询女表中所有男友的名字.
女表tf ,
+------+------+------+
| id   | name | bf   |
+------+------+------+
|    1 | fa   |    2 |
|    2 | fb   |    3 |
|    3 | fc   |    4 |
|    4 | fd   |    2 |
+------+------+------+
男表tm
+------+------+
| id   | name |
+------+------+
|    1 | ma   |
|    2 | mb   |
|    3 | mc   |
+------+------+

#左外连接
select tf.*,tm.name
from tf
left outer join tm
on tf.bf=tm.id
order by id;
+------+------+------+------+
| id   | name | bf   | name |
+------+------+------+------+
|    1 | fa   |    2 | mb   |
|    2 | fb   |    3 | mc   |
|    3 | fc   |    4 | NULL |
|    4 | fd   |    2 | mb   |
+------+------+------+------+

#右外连接
select tf.*,tm.name
from tm
right outer join tf
on tf.bf=tm.id;
结果同上

#查询男表中所有的女友的名字.
select tm.*,tf.name gf
from tm
left outer join tf
on tf.bf=tm.id
order by id;
+------+------+------+
| id   | name | gf   |
+------+------+------+
|    1 | ma   | NULL |
|    2 | mb   | fd   |
|  ' 2 | mb   | fa  '|
|    3 | mc   | fb   |
+------+------+------+
'相同字段有多个返回值的时候会自动重复多行显示.'

# 全外连接(mysql不支持)full outer join
select tf.*,tm.*
from tf
full outer join tm
on tf.bf=tm.id
所得结果为以下两者的合集:
查询女表中所有男友的名字.
查询男表中所有女友的名字.
全外连接=内连接结果+表1有表2无+表2有表1无

# 交叉连接
select tf.*,tm.*
from tf
cross join tm;
结果为笛卡尔乘积
+------+------+------+------+------+
| id   | name | bf   | id   | name |
+------+------+------+------+------+
|    1 | fa   |    2 |    1 | ma   |
|    1 | fa   |    2 |    2 | mb   |
|    1 | fa   |    2 |    3 | mc   |
|    2 | fb   |    3 |    1 | ma   |
|    2 | fb   |    3 |    2 | mb   |
|    2 | fb   |    3 |    3 | mc   |
|    3 | fc   |    4 |    1 | ma   |
|    3 | fc   |    4 |    2 | mb   |
|    3 | fc   |    4 |    3 | mc   |
|    4 | fd   |    2 |    1 | ma   |
|    4 | fd   |    2 |    2 | mb   |
|    4 | fd   |    2 |    3 | mc   |
+------+------+------+------+------+


3. useing的使用

1 using()用于两张表的join查询,要求using()指定的列在两个表中均存在,并使用之用于join的条件。 
 示例: select a.*, b.* from a left join b using(colA); 等同于: select a.*, b.* from a left join b on a.colA = b.colA;

2 多表查询就使用多个这样的join。 
示例: select a.*, b.* from a left join b using(colA) left join c using(colB); 
要求colA在a, b中均存在,colB在a, c表中均存在。

总之,using() 只是join中指定连接条件的简写,在简单的连接中常用。在列名称不同时或连接条件复杂时就无法用了,使用 a left join b on ... 是更常见的做法。

4. (@i:=@i+1)的使用

可以在生成查询结果表的时候生成一组递增的序列号。MySQL中没有这个伪列,但是有时候要用,可以用如下方法模拟生成一列自增序号。

(1)sql示例:select (@i:=@i+5) as rownum, surname, personal_name from student, (select @i:=100) as init;

解释: 上述sql中,红色值为自定义的初始序号,蓝色值为递增规则,上述sql运行结果如下

当然一般不会这么用,简单的从1开始递增就行

select (@i:=@i+1) as rownum, surname, personal_name from student, (select @i:=0) as init;

(2) 如果是多表联查,跟上述sql类似,连查完后使用(select @i:=0)定义一个初始化序列号,并且必须给这个序列号列使用别名as aa:

select (@i:=@i+1) as rownum, A.surname, CONCAT(A.surname,A.personal_name) uname
from student A
left join student B
on A.name = B.name,
(select @i:=0) as aa;

或者
select (@i:=@i+1) as rownum, A.surname,CONCAT(A.surname,A.personal_name) uname
from student A,(select @i:=0) as aa;

5. like(binary)和regexp的使用

  • like对任意多字符匹配或任意单字符进行模糊匹配.
  • regexp支持正则表达式的匹配方式,提供比 like 更多的匹配方式.
  • binary区分大小写匹配.
select * from person where uname like '%sql%'; 
select * from person where uname like binary '%SQL%';
select * from person where uname regexp '.SQL*.';

Copyright © 2009 - Now . XPBag.com . All rights Reserved.
夜心的小站 » MySQL 函数的使用解析及SQL连接查询

提供最优质的资源集合

立即查看 了解详情