字符串函数
完整的内置字符串函数见官方手册。
字符串连接函数
有两个字符串连接函数:concat(s1,s2,s3,...,sN)和concat_ws(sep,s1,s2,s3,...,sN)。
concat()将多个字符串连接起来形成一个长字符串。它会尝试将字符全部转换为字符型,如果存在null,则直接返回null。
mysql> select concat('a','b',1),concat(1,2,3),concat('a',null);
+-------------------+---------------+------------------+
| concat('a','b',1) | concat(1,2,3) | concat('a',null) |
+-------------------+---------------+------------------+
| ab1 | 123 | NULL |
+-------------------+---------------+------------------+
1 row in set
concat_ws(sep,s1,s2,...,sN)函数是concat()函数的特殊格式,它的第一个参数sep是用于连接s1,s2,...,sN的分隔符。分隔符可以是一个字符或一个字符串,只要合理即可。如果分隔符sep为null,则返回结果null,如果s1,s2,...,sN之间出现了null,则忽略null。
mysql> select concat_ws(':','23','59','58'),concat_ws('-','1st','2nd'),concat_ws('XXX','wo','shi');
+-------------------------------+----------------------------+-----------------------------+
| concat_ws(':','23','59','58') | concat_ws('-','1st','2nd') | concat_ws('XXX','wo','shi') |
+-------------------------------+----------------------------+-----------------------------+
| 23:59:58 | 1st-2nd | woXXXshi |
+-------------------------------+----------------------------+-----------------------------+
1 row in set
mysql> select concat_ws(':','23','59',null,'58'),concat_ws(null,'1st','2nd');
+------------------------------------+-----------------------------+
| concat_ws(':','23','59',null,'58') | concat_ws(null,'1st','2nd') |
+------------------------------------+-----------------------------+
| 23:59:58 | NULL |
+------------------------------------+-----------------------------+
1 row in set
由于concat()遇到null时总会返回null,这种处理方式可能并非所期望的结果,因此可以采用concat_ws()的方式忽略null或者采用ifnull()的方式将null转换为空字符串。
lower(string)、upper(string)、left(string,x)、right(string,x)
分别是变小写、变大写、从左取x长度字符、从右取x长度字符。
mysql> select lower('Dnaiel'),upper('Daniel'),left('MaLong',3),right('Daniel',3);
+-----------------+-----------------+------------------+-------------------+
| lower('Daniel') | upper('Daniel') | left('Daniel',3) | right('Daniel',3) |
+-----------------+-----------------+------------------+-------------------+
| daniel | DANIEL | Dan | iel |
+-----------------+-----------------+------------------+-------------------+
1 row in set
填充函数
有两种:lpad(string,n,pad)和rpad(string,n,pad)。
使用pad对string最左边和最右边进行填充,直到填充后总长度为n个字符。pad可以是一个字符串,如果是字符串则从左向右取直到符合长度为止。
mysql> select lpad('ddddd',10,'x'),lpad('ddddd',10,'xy'),rpad('ddddd',10,'x');
+-----------------------+------------------------+-----------------------+
| lpad('dddddd',10,'x') | lpad('dddddd',10,'xy') | rpad('dddddd',10,'x') |
+-----------------------+------------------------+-----------------------+
| xxxxdddddd | xyxydddddd | ddddddxxxx |
+-----------------------+------------------------+-----------------------+
1 row in set
长度n可以是小于或等于string字符串长度的值,此时lpad或者rpad的作用都是从左进行字符串截取而非填充,直到长度为n。也就是说lpad和rpad函数最强约束条件是长度参数n。
mysql> select rpad('Daniel',3,'x'),lpad('Daniel',3,'x'),lpad('Daniel',0,'x');
+----------------------+----------------------+----------------------+
| rpad('Daniel',3,'x') | lpad('Daniel',3,'x') | lpad('Daniel',0,'x') |
+----------------------+----------------------+----------------------+
| Dan | Dan | |
+----------------------+----------------------+----------------------+
1 row in set
trim(string)、ltrim(string)、rtrim(sting)及trim(substring from string)
分别用来消除string行首和行尾、行首、行尾的空格以及行首行尾指定的字符串。
函数 作用
----------------------- -------------------------------
ltrim(string) 删除行首空格
rtrim(string) 删除行尾空格
trim(string) 删除行首和行尾空格
trim(substring from string) 删除行首和行尾的字符串substring
例如:
mysql> select length(trim(' Daniel ')) as A,
length(ltrim('Daniel ')) as B,
length(ltrim(' Daniel ')) as C,
length(rtrim(' Daniel ')) as D;
+---+---+---+---+
| A | B | C | D |
+---+---+---+---+
| 6 | 7 | 7 | 7 |
+---+---+---+---+
1 row in set (0.00 sec)
mysql> select trim('xy' from 'xyxabxycdxyxy');
+---------------------------------+
| trim('xy' from 'xyxabxycdxyxy') |
+---------------------------------+
| xabxycd |
+---------------------------------+
1 row in set
重复字符串repeat(string,x)
将string重复x次。
mysql> select repeat('xy',3),length(repeat(' ',3)),repeat('0',3);
+----------------+-----------------------+---------------+
| repeat('xy',3) | length(repeat(' ',3)) | repeat('0',3) |
+----------------+-----------------------+---------------+
| xyxyxy | 3 | 000 |
+----------------+-----------------------+---------------+
1 row in set
字符串替换函数replace(string,a,b)
使用字符串b替换字符串string中所有的字符串a。注意点是它们都可以是字符串。如果想要替换掉的字符串a不在string中,则不会进行替换。
mysql> select replace('woshiDanielWang','s','xxxx'),replace('woshiDanielWang','ob','xxxx');
+----------------------------------------+-----------------------------------------+
| replace('woshiDanielWang','s','xxxx') | replace('woshiDanielWang','ob','xxxx') |
+----------------------------------------+-----------------------------------------+
| woxxxxhiDanielWang | woshiDanielWang |
+----------------------------------------+-----------------------------------------+
1 row in set
字符串插入替换函数insert(string,p1,len,instead_string)
将string从位置p1开始,len个长度的字符替换为instead_string。
mysql> select insert('woshiDanielWang',6,2,'gao');
+--------------------------------------+
| insert('woshiDanielWang',6,2,'gao') |
+--------------------------------------+
| woshigaonielWang |
+--------------------------------------+
1 row in set
字符串提取substring(string,x,y)
返回string中从x位置开始y个长度的字符串。如果给出的位置不存在,则无法提取所以返回空。如果给出的长度超出,则只提取允许范围内的字符串。
mysql> select substring('AAAA',3,4) AS A,substring('AAAA',0,4) AS B,substring('AAAA',10,4) AS C,length(substring('AAAA',3,10)) AS D;
+----+---+---+---+
| A | B | C | D |
+----+---+---+---+
| AA | | | 2 |
+----+---+---+---+
1 row in set (0.00 sec)
字符串比较函数strcmp(string1,string2)
比较string1和string2的ascii码大小,从前向后依次比较。strcmp认为大小写字母是等价的,所以它们相等。且存在null时,直接返回null。
- 如果string1小于string2,返回-1。
- 如果string1等于string2,返回0。
- 如果string1大于string2,返回1。
mysql> select strcmp('a','b'),strcmp('a','A'),strcmp('b','a');
+-----------------+-----------------+-----------------+
| strcmp('a','b') | strcmp('a','A') | strcmp('b','a') |
+-----------------+-----------------+-----------------+
| -1 | 0 | 1 |
+-----------------+-----------------+-----------------+
1 row in set
mysql> select strcmp('ac','ab'),strcmp('ac','ac'),strcmp('a',null),strcmp(null,'a');
+-------------------+-------------------+------------------+------------------+
| strcmp('ac','ab') | strcmp('ac','ac') | strcmp('a',null) | strcmp(null,'a') |
+-------------------+-------------------+------------------+------------------+
| 1 | 0 | NULL | NULL |
+-------------------+-------------------+------------------+------------------+
1 row in set
关于字符串比较,另外两个函数least()和greatest()也能实现,这两个函数更多的用于取最值,特别是用于数值比较,所以在后文解释。
字符串长度函数length(string)和char_length(string)
length()返回字符串的字节数,注意不是字符数,char_length()返回的才是字符数。在SQL Server中长度函数是len(string),且返回的是字符数。
mysql> select length('woshiyigeren'),length('我');
+------------------------+--------------+
| length('woshiyigeren') | length('我') |
+------------------------+--------------+
| 12 | 3 |
+------------------------+--------------+
1 row in set
mysql> select char_length('woshiyigeren'),char_length('我');
+-----------------------------+-------------------+
| char_length('woshiyigeren') | char_length('我') |
+-----------------------------+-------------------+
| 12 | 1 |
+-----------------------------+-------------------+
1 row in set
在SQL Server中:
字符串位置函数locate(sub_str,string)、position(sub_str in string)和instr(str,sub_str)
这三个函数的作用相同,都是返回sub_str在string中的开始位置。和SQL Server中的charindex()函数功能类似。
mysql> SELECT LOCATE('ball','football'),POSITION('ball' IN 'football') ,INSTR('football','ball');
+---------------------------+--------------------------------+--------------------------+
| LOCATE('ball','football') | POSITION('ball' IN 'football') | INSTR('football','ball') |
+---------------------------+--------------------------------+--------------------------+
| 5 | 5 | 5 |
+---------------------------+--------------------------------+--------------------------+
1 row in set
字符串位置函数find_in_set(sub_string,str_set)
返回子串sub_string在str_set中的位置,其中str_set是一个由逗号隔开的多个字符串集合。如果找不到位置(sub_str不在str_set中或者str_set为空串)则返回0,如果任意一个为null,则返回null。
mysql> select find_in_set('ab','cd,ab,dc'),find_in_set('ab',''),find_in_set(null,'ab,cd');
+------------------------------+----------------------+---------------------------+
| find_in_set('ab','cd,ab,dc') | find_in_set('ab','') | find_in_set(null,'ab,cd') |
+------------------------------+----------------------+---------------------------+
| 2 | 0 | NULL |
+------------------------------+----------------------+---------------------------+
1 row in set
字符串位置函数field(s,str1,str2,...,strN)
返回字符串s在字符串集合str1,str2,...,strN中的位置。如果找不到或者字符串s为null,则返回0,因为null无法进行比较,也就是找不到。
mysql> select field('ab','abc','1ab','ab','cd') as col1,field(null,'ab','cd') as col2;
+------+------+
| col1 | col2 |
+------+------+
| 3 | 0 |
+------+------+
1 row in set (0.00 sec)
指定位置的字符串函数elt(n,str1,str2,...,strN)
elt表示从(数据)仓库中提取需要的东西。n是位置,n=1则返回str1,n=2则返回str2,依次类推。当n<1或者大于字符串的数量,则返回null。
mysql> select elt(1,'a','b','c'),elt(2,'a','b','c'),elt(0,'a','b'),elt(10,'a','b');
+--------------------+--------------------+----------------+-----------------+
| elt(1,'a','b','c') | elt(2,'a','b','c') | elt(0,'a','b') | elt(10,'a','b') |
+--------------------+--------------------+----------------+-----------------+
| a | b | NULL | NULL |
+--------------------+--------------------+----------------+-----------------+
1 row in set
字符串反转函数reverse(str)
反转字符串str的字符顺序。
mysql> select reverse('hello');
+------------------+
| reverse('hello') |
+------------------+
| olleh |
+------------------+
1 row in set (0.00 sec)
数学函数
完整的内置数学函数见官方手册。
绝对值函数ABS(x)
mysql> select abs(0.9),abs(0),abs(-0.9);
+----------+--------+-----------+
| abs(0.9) | abs(0) | abs(-0.9) |
+----------+--------+-----------+
| 0.9 | 0 | 0.9 |
+----------+--------+-----------+
1 row in set
取模函数mod(x,y)
取x/y后的余数。支持小数和负数。如果除数为0或者除数被除数有一个为null,则返回null。
mysql> select mod(31,8),mod(31.56,8),mod(-31.56,8),mod(31,0),mod(0,8);
+-----------+--------------+---------------+-----------+----------+
| mod(31,8) | mod(31.56,8) | mod(-31.56,8) | mod(31,0) | mod(0,8) |
+-----------+--------------+---------------+-----------+----------+
| 7 | 7.56 | -7.56 | NULL | 0 |
+-----------+--------------+---------------+-----------+----------+
1 row in set
四舍五入函数round(x,y)
返回值x含有y位小数的四舍五入后的结果,如果省略y,则默认y为0。
mysql> select round(3.15),round(3.15,1),round(-3.15),round(-3.15,1);
+-------------+---------------+--------------+----------------+
| round(3.15) | round(3.15,1) | round(-3.15) | round(-3.15,1) |
+-------------+---------------+--------------+----------------+
| 3 | 3.2 | -3 | -3.2 |
+-------------+---------------+--------------+----------------+
1 row in set
位数截断函数truncate(x,y)
截断x的小数位数使得最终保留y个小数位。它的用法和round(x,y)几乎一样,只不过truncate是用来截断而不用来四舍五入。不能省略y但可以等于0,且y不能为负数。
mysql> select truncate(3.156,2),truncate(3.156,0);
+-------------------+-------------------+
| truncate(3.156,2) | truncate(3.156,0) |
+-------------------+-------------------+
| 3.15 | 3 |
+-------------------+-------------------+
1 row in set
地板函数floor(x)和天花板函数ceiling(x)
地板函数返回比x小的最大整数,天花板函数返回比x大的最小整数。
mysql> select floor(3.4),floor(-3.4),ceiling(3.4),ceiling(-3.4);
+------------+-------------+--------------+---------------+
| floor(3.4) | floor(-3.4) | ceiling(3.4) | ceiling(-3.4) |
+------------+-------------+--------------+---------------+
| 3 | -4 | 4 | -3 |
+------------+-------------+--------------+---------------+
1 row in set
随机函数rand()
每次随机返回一个0-1之间不包括0和1的数,且每次运行结果都不同。
mysql> select rand(),rand();
+--------------------+----------------------+
| rand() | rand() |
+--------------------+----------------------+
| 0.7380041170287915 | 0.055543343588284534 |
+--------------------+----------------------+
1 row in set
若要取得0-100之间的数,可以使用100去乘随机值,但这样获得的函数还是不包含0和100这两个边界的。
mysql> select 100*rand(),100*rand(),100*rand();
+------------------+-------------------+--------------------+
| 100*rand() | 100*rand() | 100*rand() |
+------------------+-------------------+--------------------+
| 22.5249471352668 | 96.80735235736458 | 16.461923454387044 |
+------------------+-------------------+--------------------+
1 row in set
若要取整,则可以配合floor()或者ceiling()函数。但这样取得的是[0,99]或者[1,100],而不能是[0,100]。
mysql> select floor(100*rand()) as '[0,99]',ceiling(100*rand()) as '[1,100]';
+--------+---------+
| [0,99] | [1,100] |
+--------+---------+
| 90 | 24 |
+--------+---------+
1 row in set
如果要想获得[0-100]这样包含边界的值,可以拓宽随机值。以下是两种方法:
mysql> select ceiling(rand()*101-1),floor(rand()*101);
+-----------------------+-------------------+
| ceiling(rand()*101-1) | floor(rand()*101) |
+-----------------------+-------------------+
| 92 | 55 |
+-----------------------+-------------------+
1 row in set
最值函数least(v1,v2,v3,…,vn)
从v1,v2,v3,…,vn中取出最小值。有以下几种情况:
(1)当只有数值类型时,取数值最小的。且负数有效。
(2)当只有字符串时,从第一个字符开始向后比较ascii码,小写字母小于大写字母。
(3)数值和字符串比较,返回结果为0。若要比较,需要先将数字转换为字符串格式,且字符串类型的数字总是小于字母。
(4)当n个成员之间存在null的时候,总是返回null,因为无法比较。
mysql> select least(5,10,-1),least('ab','c','ac'),least('a',1),least('a','999'),least('a',1,null);
+----------------+----------------------+--------------+------------------+-------------------+
| least(5,10,-1) | least('ab','c','ac') | least('a',1) | least('a','999') | least('a',1,null) |
+----------------+----------------------+--------------+------------------+-------------------+
| -1 | ab | 0 | 999 | NULL |
+----------------+----------------------+--------------+------------------+-------------------+
1 row in set
最值函数greatest(v1,v2,v3,…,vn)
和least()函数相反,它取的是最大值。包括以下几种情况:
(1)当只有数值类型时,取最大值。负值有效。
(2)当只有字符串时,比较ascii码,大写字母大于小写字母。
(3)当数字和字符串比较时,数字大于字符串,即返回数字中最大值。但是字符串类型的数字小于字母。这个least()不一样。
(4)当存在null值时,返回null。
mysql> select greatest(5,10,-1) as A,
greatest('ab','c','ac') as B,
greatest('a',1) as C,
greatest('a','999') as D,
greatest('a',1,null) as E;
+----+---+---+---+------+
| A | B | C | D | E |
+----+---+---+---+------+
| 10 | c | 1 | a | NULL |
+----+---+---+---+------+
1 row in set, 2 warnings (0.00 sec)
日期时间函数
有很多很多,官方手册:日期时间函数。以下挑几个介绍。
当前日期时间
返回当前日期:curdate()、current_date(),它们是同义词;
返回当前时间:curtime()、current_time(),它们是同义词;
返回当前日期时间:now()、current_timestamp()、localtime()、localtimestamp、localtimestamp()、sysdate(),除了sysdate(),其余的都是now()的同义词。
mysql> select curdate(),current_date(),current_timestamp(),curtime(),localtime(),now(),sysdate();
注意,now()和sysdate()是不同的。now()返回的是执行SQL语句那一刻的时间(如果now()是在存储过程或函数或触发器中,则now()返回的是这些程序开始调用执行的时刻),而sysdate()返回的是实时更新的当前时间,即操作系统当前的时间。通过下面的例子就知道了:
mysql> SELECT NOW(),CURRENT_TIMESTAMP(),SYSDATE(),LOCALTIME(),SLEEP(2),NOW(),CURRENT_TIMESTAMP(),SYSDATE(),LOCALTIME()\G
*************************** 1. row ***************************
NOW(): 2022-04-11 16:47:06
CURRENT_TIMESTAMP(): 2022-04-11 16:47:06
SYSDATE(): 2022-04-11 16:47:06
LOCALTIME(): 2022-04-11 16:47:06
SLEEP(2): 0
NOW(): 2022-04-11 16:47:06
CURRENT_TIMESTAMP(): 2022-04-11 16:47:06
SYSDATE(): 2022-04-11 16:47:08 # 注意此处sleep 2秒后的时间
LOCALTIME(): 2022-04-11 16:47:06
1 row in set (2.01 sec)
可以看到,sleep(2)后,sysdate()返回的比其他的函数晚了两秒,而其他的函数返回的和sleep(2)之前的时间是一样的,且都是开始执行语句的时间。
week(DATE)
返回给定日期在当年是第几周。
mysql> select week(now());
+-------------+
| week(now()) |
+-------------+
| 12 |
+-------------+
1 row in set
year(DATE)、monthname(DATE)、day(DATE)、quarter(DATE)
返回所给日期的年份、月份、月中天(所以day()的同义词是dayofmonth()函数)以及季度,不过返回的月份是英文全名。
mysql> select year(now()),monthname(now());
+-------------+------------------+
| year(now()) | monthname(now()) |
+-------------+------------------+
| 2022 | April |
+-------------+------------------+
1 row in set (0.00 sec)
hour(TIME)、minute(TIME)、second(TIME)
返回给定时间值的小时、分钟、秒部分。
mysql> select now(),hour(now()),minute(now()),second(now());
+---------------------+-------------+---------------+---------------+
| now() | hour(now()) | minute(now()) | second(now()) |
+---------------------+-------------+---------------+---------------+
| 2022-04-11 16:49:45 | 16 | 49 | 45 |
+---------------------+-------------+---------------+---------------+
1 row in set (0.00 sec)
extract(part from DATE)
从给定的DATETIME中提取秒(second)、分(minute)、时(hour)、日(day)、月(month)、周(week)、年(year),还支持季度(quarter)提取。和SQL Server中的datepart()函数一样的功能。
mysql> select extract(year from now()) as year_part,
extract(month from now()) as month_part,
extract(day from now()) as day_part,
extract(week from now()) as week_part;
+-----------+------------+----------+-----------+
| year_part | month_part | day_part | week_part |
+-----------+------------+----------+-----------+
| 2022 | 4 | 11 | 15 |
+-----------+------------+----------+-----------+
1 row in set (0.00 sec)
mysql> select now(),extract(hour from now()) as hour_part,
extract(minute from now()) as minute_part,
extract(second from now()) as second_part;
+---------------------+-----------+-------------+-------------+
| now() | hour_part | minute_part | second_part |
+---------------------+-----------+-------------+-------------+
| 2022-04-11 16:50:51 | 16 | 50 | 51 |
+---------------------+-----------+-------------+-------------+
1 row in set (0.00 sec)
dayname(DATE)和dayofweek(DATE)
dayname返回给定日期是星期几,返回的周日期name的都是英文全名。而dayofweek返回的是数字代表的星期几,1表示周日,7表示周六。
mysql> select dayname(20131111),dayofweek('20131111');
+-------------------+-----------------------+
| dayname(20131111) | dayofweek('20131111') |
+-------------------+-----------------------+
| Monday | 2 |
+-------------------+-----------------------+
1 row in set (0.00 sec)
日期时间格式化
日期格式化:date_format(date,fmt)
时间格式化:time_format(time,fmt)
其中fmt为日期时间的描述格式,使用%开头进行描述,例如%Y表示4位数字的年份,%m表示2位数字的月份等,更多的格式见官方手册fmt
mysql> select date_format('20131012','%Y-%m-%d');
+------------------------------------+
| date_format('20131012','%Y-%m-%d') |
+------------------------------------+
| 2013-10-12 |
+------------------------------------+
1 row in set (0.00 sec)
日期时间计算
增加日期:DATE_ADD(date,interval expr unit),ADDDATE(date,interval expr unit),它们是同义词;
减去日期:DATE_SUB(date,interval expr unit),SUBDATE(date,interval expr unit),它们是同义词;
在给定日期date基础上加或减去某种格式表达的日期时间。interval是关键字,expr是用来给定加减多少时间的表达式,unit是expr要表达的日期类型,见下图。其中expr的描述方式和unit是对应的。
Unit | Description |
---|---|
MICROSECOND | Microseconds |
SECOND | Seconds |
MINUTE | Minutes |
HOUR | Hours |
DAY | Days |
WEEK | Weeks |
MONTH | Months |
QUARTER | Quarters |
YEAR | Years |
SECOND_MICROSECOND | Seconds.Microseconds |
MINUTE_MICROSECOND | Minutes.Seconds.Microseconds |
MINUTE_SECOND | Minutes.Seconds |
HOUR_MICROSECOND | Hours.Minutes.Seconds.Microseconds |
HOUR_SECOND | Hours.Minutes.Seconds |
HOUR_MINUTE | Hours.Minutes |
DAY_MICROSECOND | Days Hours.Minutes.Seconds.Microseconds |
DAY_SECOND | Days Hours.Minutes.Seconds |
DAY_MINUTE | Days Hours.Minutes |
DAY_HOUR | Days Hours |
YEAR_MONTH | Years-Months |
例如year_month单元,从上表中得出它的格式是"years month"表示计算year部分和month部分的间隔。expr中year和month之间使用任意分隔符都可以,例如"1_2"、"1!2"、"1-2"和"1 2"都是允许的。如果使用day_minute单元,它的意义是"days hours.minutes",那么expr中就需要给定3个值,这3个值从前向后分别代表日、时、分,中间可以用任意分隔符分隔,例如'3-2-1'表示3天2小时1分钟。
expr的前面可以加上"+"和"-",分别表示加和减,不写时默认为"+",所以date_add和date_sub之间通过正负符号是可以等价的。
以下是示例:
mysql> select now(),
date_add(now(),interval 31 day) as add31days,
date_add(now(),interval '1_2' year_month) as add1year2month;
+---------------------+---------------------+---------------------+
| now() | add31days | add1year2month |
+---------------------+---------------------+---------------------+
| 2022-04-11 16:52:30 | 2022-05-12 16:52:30 | 2023-06-11 16:52:30 |
+---------------------+---------------------+---------------------+
1 row in set (0.00 sec)
上述例子中使用了上面的第二列表示在当前日期内加上31天后的时间,第三列表示在当前日期基础上加上1年又2个月之后的时间。
如果date_add中expr使用的是负数,则表示减。
mysql> select now(),
date_add(now(),interval '-31' day) as jian31days,
date_add(now(),interval '-1_2' year_month) as jian1year2month;
+---------------------+---------------------+---------------------+
| now() | jian31days | jian1year2month |
+---------------------+---------------------+---------------------+
| 2022-04-11 16:52:56 | 2022-03-11 16:52:56 | 2021-02-11 16:52:56 |
+---------------------+---------------------+---------------------+
1 row in set (0.00 sec)
上面第二列表示在当前日期上减去31天后的时间,第三列表示在当前日期基础上减去1年又2个月之后的时间。
datediff(expr1,expr2)
expr1和expr2之间的天数差,是expr1减去expr2。
mysql> select now(),datediff(now(),'2023-01-01');
+---------------------+------------------------------+
| now() | datediff(now(),'2023-01-01') |
+---------------------+------------------------------+
| 2022-04-11 16:53:28 | -265 |
+---------------------+------------------------------+
1 row in set (0.00 sec)
LAST_DAY(datetime)
返回给定日期所在月的最后一天。
mysql> select last_day(now()),last_day('2016-02-03');
+-----------------+------------------------+
| last_day(now()) | last_day('2019-02-03') |
+-----------------+------------------------+
| 2022-04-30 | 2019-02-28 |
+-----------------+------------------------+
1 row in set (0.00 sec)
流程控制之条件判断函数
在MySQL/MariaDB中主要有if、ifnull和case语句进行条件判断。其中if语句和SQL Server中的if相差较大。
if(expr,true_value,false_value)
if函数用来判断expr是否为真,如果为真,则返回true_value,否则返回false_value。这和if语句是不一样的。
mysql> select if(1>2,'a','b'),if(2>1,'a','b');
+-----------------+-----------------+
| if(1>2,'a','b') | if(2>1,'a','b') |
+-----------------+-----------------+
| b | a |
+-----------------+-----------------+
1 row in set
expr判断是否为真的依据是expr的结果非0且非null。所以也可以直接使用数字表示真假,但不能使用字母表示真假。
mysql> select if(99,'a','b'),if(0,'a','b'),if(null,'a','b'),if('2','a','b'),if('c','a','b');
+----------------+---------------+------------------+-----------------+-----------------+
| if(99,'a','b') | if(0,'a','b') | if(null,'a','b') | if('2','a','b') | if('c','a','b') |
+----------------+---------------+------------------+-----------------+-----------------+
| a | b | b | a | b |
+----------------+---------------+------------------+-----------------+-----------------+
1 row in set, 1 warning (0.00 sec)
ifnull(value1,value2)
如果value1不为空则返回value1,否则返回value2。总之就是给定一个非null值。允许value2为null。
mysql> select ifnull(1,'a'),ifnull('a','b'),ifnull(null,'a'),ifnull('a',null),ifnull(null,null);
+---------------+-----------------+------------------+------------------+-------------------+
| ifnull(1,'a') | ifnull('a','b') | ifnull(null,'a') | ifnull('a',null) | ifnull(null,null) |
+---------------+-----------------+------------------+------------------+-------------------+
| 1 | a | a | a | NULL |
+---------------+-----------------+------------------+------------------+-------------------+
1 row in set
MySQL中的ifnull函数基本等价于SQL Server中的isnull()函数,跟SQL Server中的nullif函数相差非常大。且MySQL中的ifnull只能从两个参数中取一个非空值,而SQL Server中的coalesce()函数可以从多个参数中选第一个非空值。
nullif(expr1,expr2)
如果expr1等于expr2,则返回null,否则返回expr1。也就是说,两者不相等时取前者,否则取NULL。如果expr1和expr2任意一个为null,则直接返回null。这等价于:
case when expr1 = expr2 || expr1 is null || expr2 is null then null
else expr1
end
例如:
mysql> select nullif(1,1),nullif(1,2),nullif(null,1);
+-------------+-------------+----------------+
| nullif(1,1) | nullif(1,2) | nullif(null,1) |
+-------------+-------------+----------------+
| NULL | 1 | NULL |
+-------------+-------------+----------------+
1 row in set (0.00 sec)
case语句
和SQL Server中的case语法差不多。也是两种格式:case when ...then...else...end
和case ...when...then...else...end
:
-- 格式一:
CASE WHEN express_1 THEN value_1
WHEN express_2 THEN value_2
…
ELSE value_n
END;
-- 格式二:
CASE express WHEN value1 THEN value_1
WHEN value2 THEN value_2
...
ELSE value_n
END;
注意,如果采用CASE...WHEN
的写法格式,则express只能与value进行等同性检查。例如:
/*格式一示例*/
SELECT StudentID,
CASE WHEN Mark < 60 THEN '不及格'
WHEN Mark >= 60 AND Mark < 70 THEN '及格'
WHEN Mark >= 70 AND Mark < 80 THEN '良好'
ELSE '优秀'
END
FROM Tscore;
/*格式二示例*/
SELECT StudentID ,
CASE FLOOR(Mark / 10)
WHEN 5 THEN '不及格'
WHEN 6 THEN '及格'
WHEN 7 THEN '良好'
ELSE '优秀'
END
FROM Tscore;
其中格式二为case ... when
的格式,它的when部分的值都只能和floor(mark/10)做等于号比较,这是等同性检查。而格式一的写法就灵活的多,既可以做等号比较,也能做大于号或其他方式的比较。
类型转换函数cast()和convert()
类型转换函数用来转换数据类型。在MySQL/MariaDB中可以转换的类型有以下几种:
二进制: BINARY[(N)]
字符型: CHAR[(N)]
日期 : DATE
时间: TIME
日期时间型 : DATETIME
浮点数 : DECIMAL
整数 : SIGNED
无符号整数 : UNSIGNED
其中convert()有两种语法:
CONVERT(expr,type), CONVERT(expr USING transcoding_name)
后者用于不同字符集之间转换数据。
在转换数据类型时,cast和convert的功能基本是一样的,只是写法不同。
mysql> SELECT CAST('3.35' AS signed);
+------------------------+
| CAST('3.35' AS signed) |
+------------------------+
| 3 |
+------------------------+
1 row in set
mysql> SELECT CAST(100 AS CHAR(2)),CONVERT('2013-8-9 12:12:12',TIME);
+----------------------+-----------------------------------+
| CAST(100 AS CHAR(2)) | CONVERT('2013-8-9 12:12:12',TIME) |
+----------------------+-----------------------------------+
| 10 | 12:12:12 |
+----------------------+-----------------------------------+
1 row in set
带有using的convert函数用来转换字符集。
mysql> SELECT CHARSET('string'),CHARSET(CONVERT('string' USING latin1));
+-------------------+-----------------------------------------+
| CHARSET('string') | CHARSET(CONVERT('string' USING latin1)) |
+-------------------+-----------------------------------------+
| utf8mb4 | latin1 |
+-------------------+-----------------------------------------+
1 row in set
其它实用函数
-
sleep(N)
延迟N秒后执行后面的语句。特殊点在于sleep()函数可以用于select的选择列表。
select a,sleep(2),a from t;
注意上面的语句中,是先查询a,再阻塞2秒,之后再查询a,而不是先阻塞后再查询两次a或查询两次a后再阻塞。也就是说,对于mysql/mariadb来说,select的选择列表之间是有先后顺序的,不像sql server,选择列之间是完全平行等价的。可以通过下面的例子来验证:
select sysdate(),sleep(1),sysdate();
-
返回当前数据库名database()
-
返回当前数据库版本version()
-
返回当前登录用户名user()
mysql> select database(),version(),user(); +------------+-----------+----------------+ | database() | version() | user() | +------------+-----------+----------------+ | test | 5.7.37 | root@localhost | +------------+-----------+----------------+ 1 row in set (0.00 sec)
-
返回加密字符串password(str)
-
返回字符串的MD5值md5(str)
mysql> select password('abc'),md5('abc'); +-------------------------------------------+----------------------------------+ | password('abc') | md5('abc') | +-------------------------------------------+----------------------------------+ | *0D3CED9BEC10A777AEC23CCC353A8C08A633045E | 900150983cd24fb0d6963f7d28e17f72 | +-------------------------------------------+----------------------------------+ 1 row in set
-
last_insert_id()函数
LAST_INSERT_ID()返回最后一个INSERT或UPDATE为AUTO_INCREMENT列设置的第一个发生的值。该函数值不是基于表的,这一点和SQL Server是不同的,也就是说,对a表插入的最后一个值是10,再对b表插入的最后一个值是15,那么函数返回的将是15。并且last_insert_id的值和一次插入一条记录还是一次批量插入的方式有关。mysql> create table test10(id int primary key auto_increment,name char(20)); # 一次插入一条记录。 mysql> insert into test10 values(null,'gaoxiaofang'); mysql> insert into test10 values(null,'malongshuai'); mysql> insert into test10 values(null,'longshuai'); mysql> insert into test10 values(null,'xiaofang'); mysql> select * from test10; +----+-------------+ | id | name | +----+-------------+ | 1 | gaoxiaofang | | 2 | malongshuai | | 3 | longshuai | | 4 | xiaofang | +----+-------------+ 4 rows in set
查看last_insert_id的值,结果将是4。
mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 4 | +------------------+ 1 row in set
一次插入多条记录,并查看last_insert_id()的值。
mysql> insert into test10 values(null,'tun\'er'),(null,'woniu'),(null,'wugui'); mysql> select *,last_insert_id() from test10; +----+-------------+------------------+ | id | name | last_insert_id() | +----+-------------+------------------+ | 1 | gaoxiaofang | 5 | | 2 | malongshuai | 5 | | 3 | longshuai | 5 | | 4 | xiaofang | 5 | | 5 | tun'er | 5 | | 6 | woniu | 5 | | 7 | wugui | 5 | +----+-------------+------------------+ 7 rows in set
可以发现这里last_insert_id的值不是7而是5,这是因为批量插入的时候last_insert_id的值将会是批量中的第一条记录的自增列值。 且last_insert_id的值和表是无关的,只和会话环境有关。例如再向另外一个表插入后,last_insert_id的值将变为另一个值。
mysql> create table test11(id int primary key auto_increment,name char(20)); mysql> insert into test11 values(null,'gaoxiaofang'); mysql> insert into test11 values(null,'malongshuai'); mysql> insert into test11 values(null,'longshuai'); mysql> insert into test11 values(null,'xiaofang'); mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 4 | +------------------+ 1 row in set
可以发现它又变回了4。
Comments NOTHING