对于任何编程语言来说,内置函数都是其精髓。将简单的语法封装成某种方法,供需调用。函数是语法和需求的封装,亦是过程,对象以及类的基础,因此通过对函数的掌握程度可以反映出对一门语言的理解,这不仅是技术,更是一门艺术。
SQL作为数据库的操作语言而被赋予了更多的头衔,其简单的语法更是被DBA所热爱,不过要了解,愈是简单的语言,其精髓就愈难掌握。更何况,SQL语言不仅有标准版(普通话),还有各产品厂商根据需求修改的拓展SQL(方言)。由于DBA的工作特殊性,即使骨灰级别的DBA也不能保证会在写SQL时不报语法错误,而数据层的操作对安全性的要求又往往非常高。因此,越资深的DBA越是用简单的语法操作,查询出数据后交给应用去处理,避免对数据产生的悲剧。关于这一点,个人人为从业务的角度出发更为合适。如果您的数据库时OLAP业务,那么在数据库执行绝对会比应用执行的效率高,原因很简单——应用需要从网络接收数据库发送过来的大量数据,对网络有较大的压力。应用在获得原始数据后还要进行运算再返回给用户端,这对用户端略显冷漠了。而针对OLTP的业务,拜托,CPU对处理线程和事务的压力已经力不从心了,还让它来计算数据?前面有个Redis才勉强活命啊,还是乖乖交给应用去处理数据吧。
MySQL 5.7 官方共有442个内置函数,抛去小版本失效的有381个函数,这么多函数估计很少有人能全都背下来,而且在日常的工作中全部都能用上的也是微乎其微,因此,笔者总结了部分常用的函数说明及用法,同各位一起分享。(原图分享:MySQL常用函数 提取码:b94x)
上图为MySQL常用的一些函数,当然如果您想学习全部函数可以参考官档的第十二章(Chapter 12 Functions and Operators),里面有详细的语法和说明。
下面我们来验证一下这些函数,首先我们建立一张名为emp的表,结构如下:
CREATE TABLE `emp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`dep` enum('SALE','IT','HR','FD') COLLATE utf8mb4_bin DEFAULT NULL,
`salary` float DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
之后我们再插入一些数据,最后这种表的内容如下:
mysql> select * from emp;
+----+-------+------+------+--------+
| id | name | age | dep | salary |
+----+-------+------+------+--------+
| 1 | Will | 18 | IT | 12000 |
| 2 | Jack | 26 | IT | 15000 |
| 3 | Lucy | 20 | FD | 8000 |
| 4 | Lily | 21 | FD | 8500 |
| 5 | Alice | 25 | HR | 9000 |
| 6 | Felix | 19 | SALE | 5000 |
| 7 | James | 30 | SALE | 6500 |
| 8 | Bill | 28 | SALE | 6500 |
| 9 | Anddy | 19 | IT | 15000 |
| 10 | Leo | 31 | HR | 10000 |
| 11 | Lee | 22 | SALE | NULL |
| 12 | Adele | NULL | SALE | NULL |
+----+-------+------+------+--------+
OK,这是一张普通的员工信息表,id为主键,之后的字段均没有非空约束,下面我们来用这张表验证一下这些常用函数。
用途:连接s1,s2,......sn为一个字符串,有NULL返回值为NULL
mysql> select concat(name,'-',age,'-',dep,'-',salary) from emp;
+-----------------------------------------+
| concat(name,'-',age,'-',dep,'-',salary) |
+-----------------------------------------+
| Will-18-IT-12000 |
| Jack-26-IT-15000 |
| Lucy-20-FD-8000 |
| Lily-21-FD-8500 |
| Alice-25-HR-9000 |
| Felix-19-SALE-5000 |
| James-30-SALE-6500 |
| Bill-28-SALE-6500 |
| Anddy-19-IT-15000 |
| Leo-31-HR-10000 |
| NULL |
| NULL |
+-----------------------------------------+
用途:将字符串str从第x位开始,y个字符长的子串替换为字符串instr
mysql> select insert(name,2,1,age) from emp where id = 1;
+----------------------+
| insert(name,2,1,age) |
+----------------------+
| W18ll |
+----------------------+
用途:将字符串str当中所有字符变为小写
mysql> select lower(dep) from emp where id = 3;
+------------+
| lower(dep) |
+------------+
| fd |
+------------+
用途:将字符串str中所有字符变为大写
mysql> select upper(name) from emp where id = 2;
+-------------+
| upper(name) |
+-------------+
| JACK |
+-------------+
用途:返回字符串str左边的x个字符
mysql> select left(salary,2) from emp where id = 4;
+----------------+
| left(salary,2) |
+----------------+
| 85 |
+----------------+
用途:返回字符串str右边的x个字符
mysql> select right(name,1) from emp where id = 5;
+---------------+
| right(name,1) |
+---------------+
| e |
+---------------+
用途:用字符串pad对str最左边进行填充,直到长度为n个字符串长度
mysql> select lpad(name,10,age) from emp where id = 6;
+-------------------+
| lpad(name,10,age) |
+-------------------+
| 19191Felix |
+-------------------+
用途:用字符串pad对str最右边进行填充,直到长度为n个字符串长度
mysql> select rpad(name,10,age) from emp where id = 7;
+-------------------+
| rpad(name,10,age) |
+-------------------+
| James30303 |
+-------------------+
用途:去掉字符串str左侧的空格
mysql> select lpad(name,10,' ') from emp where id = 1;
+-------------------+
| lpad(name,10,' ') |
+-------------------+
| Will |
+-------------------+
1 row in set (0.00 sec)
mysql> select ltrim(lpad(name,10,' ')) from emp where id = 1;
+--------------------------+
| ltrim(lpad(name,10,' ')) |
+--------------------------+
| Will |
+--------------------------+
用途:去掉字符串str行尾的空格
mysql> select concat(rpad(name,10,' '),'*') from emp where id = 1;
+-------------------------------+
| concat(rpad(name,10,' '),'*') |
+-------------------------------+
| Will * |
+-------------------------------+
1 row in set (0.22 sec)
mysql> select concat(rtrim(rpad(name,10,' ')),'*') from emp where id = 1;
+--------------------------------------+
| concat(rtrim(rpad(name,10,' ')),'*') |
+--------------------------------------+
| Will* |
+--------------------------------------+
用途:去掉字符串str两端的空格
mysql> select concat(rpad(lpad(name,10,' '),20,' '),'*') from emp where id = 1;
+--------------------------------------------+
| concat(rpad(lpad(name,10,' '),20,' '),'*') |
+--------------------------------------------+
| Will * |
+--------------------------------------------+
1 row in set (0.00 sec)
mysql> select concat(trim(rpad(lpad(name,10,' '),20,' ')),'*') from emp where id = 1;
+--------------------------------------------------+
| concat(trim(rpad(lpad(name,10,' '),20,' ')),'*') |
+--------------------------------------------------+
| Will* |
+--------------------------------------------------+
用途:重复显示x次str
mysql> select repeat(name,3) from emp where id = 1;
+----------------+
| repeat(name,3) |
+----------------+
| WillWillWill |
+----------------+
用途:a为字符串str中的子串,将a替换成b,显示新的str字符串
mysql> select replace(name,'ill','ahaha') from emp where id = 1;
+-----------------------------+
| replace(name,'ill','ahaha') |
+-----------------------------+
| Wahaha |
+-----------------------------+
用途:比较字符串s1和s2的ASCII码值的大小,s1 < s2 返回 -1; s1 = s2 返回 0; s1 > s2 返回 1;
mysql> select strcmp((select age from emp where id = 1),(select age from emp where id = 2));
+-------------------------------------------------------------------------------+
| strcmp((select age from emp where id = 1),(select age from emp where id = 2)) |
+-------------------------------------------------------------------------------+
| -1 |
+-------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select strcmp((select dep from emp where id = 1),(select dep from emp where id = 2));
+-------------------------------------------------------------------------------+
| strcmp((select dep from emp where id = 1),(select dep from emp where id = 2)) |
+-------------------------------------------------------------------------------+
| 0 |
+-------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select strcmp((select name from emp where id = 1),(select name from emp where id = 2));
+---------------------------------------------------------------------------------+
| strcmp((select name from emp where id = 1),(select name from emp where id = 2)) |
+---------------------------------------------------------------------------------+
| 1 |
+---------------------------------------------------------------------------------+
用途:返回从字符串str的x位置起的y个字符长度的字符串
mysql> select substring(name,2,1) from emp where id = 12;
+---------------------+
| substring(name,2,1) |
+---------------------+
| d |
+---------------------+
用途:返回字符串的长度
mysql> select char_length(name) from emp where id = 9;
+-------------------+
| char_length(name) |
+-------------------+
| 5 |
+-------------------+
用途:将s1,s2,...sn用separator连接符连接成一个字符串,忽略NULL
mysql> select concat_ws('-',name,age,dep,salary) from emp where id = 8;
+------------------------------------+
| concat_ws('-',name,age,dep,salary) |
+------------------------------------+
| Bill-28-SALE-6500 |
+------------------------------------+
用途:将from_base进制表示的字符串N用to_base进制表示
mysql> select conv(age,10,2) from emp where id = 5;
+----------------+
| conv(age,10,2) |
+----------------+
| 11001 |
+----------------+
用途:将数字X以四舍五入的方式保留小数点后D位,并将结果以字符串的形式返回
mysql> select format(salary,3) from emp where id = 4;
+------------------+
| format(salary,3) |
+------------------+
| 8,500.000 |
+------------------+
用途:将字符串str反转输出
mysql> select reverse(name) from emp where id = 7;
+---------------+
| reverse(name) |
+---------------+
| semaJ |
+---------------+
用途:返回数字x的绝对值
mysql> select age,-age from emp where id = 6;
+------+------+
| age | -age |
+------+------+
| 19 | -19 |
+------+------+
1 row in set (0.00 sec)
mysql> select abs(age),abs(-age) from emp where id = 6;
+----------+-----------+
| abs(age) | abs(-age) |
+----------+-----------+
| 19 | 19 |
+----------+-----------+
用途:返回大于x的最小整数
mysql> select salary/0.618 from emp where id = 10;
+--------------------+
| salary/0.618 |
+--------------------+
| 16181.229773462783 |
+--------------------+
1 row in set (0.00 sec)
mysql> select ceil(salary/0.618) from emp where id = 10;
+--------------------+
| ceil(salary/0.618) |
+--------------------+
| 16182 |
+--------------------+
用途:返回小于x的最大整数
mysql> select salary/0.618 from emp where id = 10;
+--------------------+
| salary/0.618 |
+--------------------+
| 16181.229773462783 |
+--------------------+
1 row in set (0.00 sec)
mysql> select floor(salary/0.618) from emp where id = 10;
+---------------------+
| floor(salary/0.618) |
+---------------------+
| 16181 |
+---------------------+
用途:返回 x/y 的模
mysql> select salary,age,mod(salary,age) from emp where id = 9;
+--------+------+-----------------+
| salary | age | mod(salary,age) |
+--------+------+-----------------+
| 15000 | 19 | 9 |
+--------+------+-----------------+
用途:返回 0~1 内的随机值
mysql> select rand();
+---------------------+
| rand() |
+---------------------+
| 0.32794184640789575 |
+---------------------+
用途:返回 x 保留 y 位小数的四舍五入的值
mysql> select salary/0.618,round(salary/0.618,4) from emp where id = 7;
+-------------------+-----------------------+
| salary/0.618 | round(salary/0.618,4) |
+-------------------+-----------------------+
| 10517.79935275081 | 10517.7994 |
+-------------------+-----------------------+
用途:返回 x 截断保留 y 位小数的值
mysql> select salary/0.618,truncate(salary/0.618,4) from emp where id = 7;
+-------------------+--------------------------+
| salary/0.618 | truncate(salary/0.618,4) |
+-------------------+--------------------------+
| 10517.79935275081 | 10517.7993 |
+-------------------+--------------------------+
用途:返回指定列col的平均值
mysql> select dep,avg(age) from emp group by dep;
+------+----------+
| dep | avg(age) |
+------+----------+
| SALE | 24.7500 |
| IT | 21.0000 |
| HR | 28.0000 |
| FD | 20.5000 |
+------+----------+
用途:返回col列非空值的个数
mysql> select count(id),count(age) from emp;
+-----------+------------+
| count(id) | count(age) |
+-----------+------------+
| 12 | 11 |
+-----------+------------+
用途:返回指定列col的最小值
mysql> select min(age) from emp;
+----------+
| min(age) |
+----------+
| 18 |
+----------+
用途:返回指定列col的最大值
mysql> select max(age) from emp;
+----------+
| max(age) |
+----------+
| 31 |
+----------+
用途:返回指定列col的所有值的和
mysql> select sum(salary) from emp;
+-------------+
| sum(salary) |
+-------------+
| 95500 |
+-------------+
用途:将分组后的col值拼接成一个字符串
mysql> select dep,group_concat(name,age,salary) from emp group by dep;
+------+--------------------------------------+
| dep | group_concat(name,age,salary) |
+------+--------------------------------------+
| SALE | Felix195000,James306500,Bill286500 |
| IT | Will1812000,Jack2615000,Anddy1915000 |
| HR | Alice259000,Leo3110000 |
| FD | Lucy208000,Lily218500 |
+------+--------------------------------------+
用途:返回当前系统的日期
mysql> select curdate();
+------------+
| curdate() |
+------------+
| 2019-04-12 |
+------------+
用途:返回当前系统的时间
mysql> select curtime();
+-----------+
| curtime() |
+-----------+
| 23:25:12 |
+-----------+
用途:返回当前系统的日期和时间
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2019-04-12 23:26:45 |
+---------------------+
用途:返回日期date的UNIX时间戳
mysql> select unix_timestamp(20190410);
+--------------------------+
| unix_timestamp(20190410) |
+--------------------------+
| 1554825600 |
+--------------------------+
用途:返回timestamp时间戳所对应的日期和时间
mysql> select from_unixtime(1554825615);
+---------------------------+
| from_unixtime(1554825615) |
+---------------------------+
| 2019-04-10 00:00:15 |
+---------------------------+
用途:返回date为一年中的第几周
mysql> select week(20190412);
+----------------+
| week(20190412) |
+----------------+
| 14 |
+----------------+
用途:返回date为一年中的第几个月
mysql> select month(20190412);
+-----------------+
| month(20190412) |
+-----------------+
| 4 |
+-----------------+
用途:返回日期date的年份
mysql> select year(20190412);
+----------------+
| year(20190412) |
+----------------+
| 2019 |
+----------------+
用途:返回time的小时值
mysql> select now(),hour(now());
+---------------------+-------------+
| now() | hour(now()) |
+---------------------+-------------+
| 2019-04-12 23:49:32 | 23 |
+---------------------+-------------+
用途:返回time的分钟值
mysql> select now(),minute(now());
+---------------------+---------------+
| now() | minute(now()) |
+---------------------+---------------+
| 2019-04-12 23:51:15 | 51 |
+---------------------+---------------+
用途:返回date的月份名
mysql> select monthname(now());
+------------------+
| monthname(now()) |
+------------------+
| April |
+------------------+
用途:返回与所给日期date相差INTERVAL时间间隔的日期或日期和时间(与date形式有关)
mysql> select date_add(curdate(),interval 1 month);
+--------------------------------------+
| date_add(curdate(),interval 1 month) |
+--------------------------------------+
| 2019-05-12 |
+--------------------------------------+
1 row in set (0.00 sec)
mysql> select date_add(now(),interval 1 month);
+----------------------------------+
| date_add(now(),interval 1 month) |
+----------------------------------+
| 2019-05-12 23:57:43 |
+----------------------------------+
用途:返回起始时间expr和结束时间expr2之间的天数(原图函数名错误,多写了个‘_’)
mysql> select datediff(date_add(now(),interval 1 week),now());
+-------------------------------------------------+
| datediff(date_add(now(),interval 1 week),now()) |
+-------------------------------------------------+
| 7 |
+-------------------------------------------------+
用途:返回按fmt格式化后的date日期
mysql> select date_format(now(),'%Y-%M-%D/%h:%m:%s');
+----------------------------------------+
| date_format(now(),'%Y-%M-%D/%h:%m:%s') |
+----------------------------------------+
| 2019-April-13th/12:04:04 |
+----------------------------------------+
用途:返回date的星期名
mysql> select dayname(curdate());
+--------------------+
| dayname(curdate()) |
+--------------------+
| Saturday |
+--------------------+
用途:返回date所代表的一周中的第几天(1~7)
mysql> select curdate(),dayname(now()),dayofweek(now());
+------------+----------------+------------------+
| curdate() | dayname(now()) | dayofweek(now()) |
+------------+----------------+------------------+
| 2019-04-13 | Saturday | 7 |
+------------+----------------+------------------+
用途:返回date是月中的第几天(1~31)
mysql> select curdate(),dayofmonth(date_add(date_add(curdate(),interval 2 week),interval 3 day));
+------------+--------------------------------------------------------------------------+
| curdate() | dayofmonth(date_add(date_add(curdate(),interval 2 week),interval 3 day)) |
+------------+--------------------------------------------------------------------------+
| 2019-04-13 | 30 |
+------------+--------------------------------------------------------------------------+
用途:返回date是年中的第几天(1~366)
mysql> select dayofyear(now());
+------------------+
| dayofyear(now()) |
+------------------+
| 103 |
+------------------+
用途:返回date在一年中的第几季度(1~4)
mysql> select monthname(now()),quarter(now());
+------------------+----------------+
| monthname(now()) | quarter(now()) |
+------------------+----------------+
| April | 2 |
+------------------+----------------+
用途:如果 value 是真,返回 t;否则返回 f
mysql> select age,if(age<=20,'young','old') from emp where id = 1;
+------+---------------------------+
| age | if(age<=20,'young','old') |
+------+---------------------------+
| 18 | young |
+------+---------------------------+
用途:如果 value1 不为空,返回 value1,否则返回 value2
mysql> select age,ifnull(age,'None') from emp where id = 12;
+------+--------------------+
| age | ifnull(age,'None') |
+------+--------------------+
| NULL | None |
+------+--------------------+
用途:如果 value1 等于 value2 返回 NULL,否则返回 value1
mysql> select nullif((select salary from emp where id = 7),(select salary from emp where id = 8)) union all (select salary from emp where id=7 or id=8);
+-------------------------------------------------------------------------------------+
| nullif((select salary from emp where id = 7),(select salary from emp where id = 8)) |
+-------------------------------------------------------------------------------------+
| NULL |
| 6500 |
| 6500 |
+-------------------------------------------------------------------------------------+
用途:如果 value1 是真,返回 result1,否则返回 default;如果 expr 等于 value1,返回 result1,否则返回 default
mysql> select (case when salary >= 10000 then 'high' when salary < 10000 and salary>= 8000 then 'middle' else 'low' end)as level from emp;
+--------+
| level |
+--------+
| high |
| high |
| middle |
| middle |
| middle |
| low |
| low |
| low |
| high |
| high |
| low |
| low |
+--------+
用途:计算字符串str的MD5校验和
mysql> select md5(name) from emp where id = 5;
+----------------------------------+
| md5(name) |
+----------------------------------+
| 64489c85dc2fe0787b85cd87214b3810 |
+----------------------------------+
用途:返回字符串str的加密值
mysql> select age,password(age) from emp where id = 10;
+------+-------------------------------------------+
| age | password(age) |
+------+-------------------------------------------+
| 31 | *7F81E59BDEBACE617D49AB7DE5ACA6018A9DDF20 |
+------+-------------------------------------------+
用途:返回当前所在的数据库名
mysql> select database();
+------------+
| database() |
+------------+
| db1 |
+------------+
用途:返回当前使用的数据库版本
mysql> select version();
+------------+
| version() |
+------------+
| 5.7.25-log |
+------------+
用途:返回当前登录数据库的用户名
mysql> select user();
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
用途:返回IP地址的数字形式
mysql> select INET_ATON('192.168.43.210');
+-----------------------------+
| INET_ATON('192.168.43.210') |
+-----------------------------+
| 3232246738 |
+-----------------------------+
用途:返回数字代表的IP地址
mysql> select inet_ntoa(3232246738);
+-----------------------+
| inet_ntoa(3232246738) |
+-----------------------+
| 192.168.43.210 |
+-----------------------+
其实开始我也没有明白把ip转换成数字有什么用,后来看了《MySQL深入浅出》才了解,ip转换成数字型时候可以进行一些列的运算。比如数据库中有一张表记录了某安全组中主机ip地址,我们先虚拟一张ip表进行操作,表结构如下:
CREATE TABLE `ip_t` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`host` varchar(32) COLLATE utf8mb4_bin NOT NULL,
`ip` varchar(15) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `host` (`host`),
UNIQUE KEY `ip` (`ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
之后我们插入一些数据,最后表中内容如下:
mysql> select * from ip_t;
+----+-----------------+-----------------+
| id | host | ip |
+----+-----------------+-----------------+
| 1 | es_appserver_01 | 100.100.100.61 |
| 2 | es_appserver_02 | 100.100.100.63 |
| 3 | db_appserver_01 | 100.100.100.62 |
| 4 | db_appserver_02 | 100.100.100.64 |
| 5 | mt_appserver_01 | 100.100.100.201 |
| 6 | mt_appserver_02 | 100.100.100.202 |
+----+-----------------+-----------------+
假设我想知道在100.100.100.50~100.100.100.200之间有哪些已用的ip,这时就需要使用上述的两个函数来进行比较了:
mysql> select id,host,ip from ip_t where inet_aton(ip)>=inet_aton('100.100.100.50') and inet_aton(ip)<=inet_aton('100.100.100.200');
+----+-----------------+----------------+
| id | host | ip |
+----+-----------------+----------------+
| 1 | es_appserver_01 | 100.100.100.61 |
| 2 | es_appserver_02 | 100.100.100.63 |
| 3 | db_appserver_01 | 100.100.100.62 |
| 4 | db_appserver_02 | 100.100.100.64 |
+----+-----------------+----------------+
而如果进行字符串的比较则会返回空集,因为字符串是按位比较‘5’显然是大于‘2’的,所以无法通过字符串比较来找到50~200之间的ip。
创建语法:
delimiter // # 修改结束符
create fuction func(a int,b int) # 定义函数
returns int # 返回数据类型
BEGIN # 函数体
declare num int;
set num = a + b
return(num)
END //
delimiter ; #还原结束符
我们创建了一个计算两个整数合的自定义函数,让我们来验证一下:
mysql> select plus(5,6);
+-----------+
| plus(5,6) |
+-----------+
| 11 |
+-----------+
OK,以上就是 MySQL 中的常用函数,任何技能都需要频繁练习使用才能掌握,编程无捷径,只能多码砖,与君共勉!!!