MySQL中一些非常规的函数使用总结

前言

兜兜转转,因为各种各样的事情,已经一年多没有更新博客了,虽然一年过去了,但技术依旧很菜,菜就要多努力,所以还是那句话:脚踏实地,不急不躁,不以物喜,不以己悲,接着学习吧。

测试使用的mysql版本:5.7.20。

  • 本文所涉及到的函数包括concatconcat_wsgroup_concatfind_in_setleftrightfield等。

1. concat(str1,str2,...)函数

相比大家应该都使用过concat()函数吧,用来连接多个字符串,该方法比较简单:

mysql> select concat('a','-','b','-','c');
+-----------------------------+
| concat('a','-','b','-','c') |
+-----------------------------+
| a-b-c                       |
+-----------------------------+
1 row in set (0.00 sec)

不过,需要注意的是,如果参数有一个为null,则返回值直接为null。

mysql> select concat('a','-','b',null,'c');
+------------------------------+
| concat('a','-','b',null,'c') |
+------------------------------+
| NULL                         |
+------------------------------+
1 row in set (0.00 sec)

2. concat_ws(separator,str1,str2...)函数

该方法和concat有些相似,用于连接多个字符串,不过该参数用于指定字符串连接参数之间的分隔符;也就是说,当我们使用concat时,如果连接的参数比较多,并且连接的符号都是一样的,可以使用该函数。

其中,第一个参数表示分隔符。

mysql> select concat_ws('-', 'a', 'b', 'c', 'd');
+------------------------------------+
| concat_ws('-', 'a', 'b', 'c', 'd') |
+------------------------------------+
| a-b-c-d                            |
+------------------------------------+
1 row in set (0.00 sec)

如果要连接的字符串中有一个值是null的,那么不会把该null值进行连接到字符串中:

mysql> select concat_ws('-', 'a', 'b', 'c', null,'d');
+-----------------------------------------+
| concat_ws('-', 'a', 'b', 'c', null,'d') |
+-----------------------------------------+
| a-b-c-d                                 |
+-----------------------------------------+
1 row in set (0.00 sec)

分割符不能是null,而如果分隔符是null的话,那么返回值就直接为null:

mysql> select concat_ws(null, 'a', 'b', 'c', null,'d');
+------------------------------------------+
| concat_ws(null, 'a', 'b', 'c', null,'d') |
+------------------------------------------+
| NULL                                     |
+------------------------------------------+
1 row in set (0.00 sec)

3. group_concat函数

函数格式:

group_concat([DISTINCT] 字段1,字段2 [order by 排序字段] [separator '分隔符'])

将查询结果中的值连接起来,默认使用逗号作为分隔符,然后返回一个字符串结果;如果有group by操作,就表示将同一个分组中的值连接起来,也就是分组后相同行组合。

备注:

  • 通过使用distinct可以排除重复值;如果希望对结果中的值进行排序,可以使用order by子句;separator是一个字符串值,缺省为一个逗号;
  • 在有group by的查询语句中,select指定的字段要么就包含在group by语句的后面,作为分组的依据,要么就包含在聚合函数中(max, min, avg, sum, count);

以下简单举个例子,测试数据如下:

mysql> select * from student;
+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  1 | 刘备   | 语文   | 92    |
|  2 | 关羽   | 语文   | 89    |
|  3 | 张飞   | 语文   | 90    |
|  4 | 刘备   | 数学   | 82    |
|  5 | 关羽   | 数学   | 94    |
|  6 | 张飞   | 数学   | 71    |
|  7 | 刘备   | 英语   | 88    |
|  8 | 关羽   | 英语   | 90    |
|  9 | 张飞   | 英语   | 97    |
+----+--------+--------+-------+

我们以name分组,把name相同的打印在同一行,以逗号分隔;

mysql> select name,group_concat(score) from student group by name;
+--------+---------------------+
| name   | group_concat(score) |
+--------+---------------------+
| 关羽   | 89,94,90            |
| 刘备   | 92,82,88            |
| 张飞   | 90,71,97            |
+--------+---------------------+
3 rows in set (0.00 sec)

可以看到,根据name进行分组后的score,已经通过逗号连接在一起;如果我们不想使用逗号进行分割,比如想使用分号进行分割:

mysql> select name,group_concat(score separator ';') from student group by name;
+--------+-----------------------------------+
| name   | group_concat(score separator ';') |
+--------+-----------------------------------+
| 关羽   | 89;94;90                          |
| 刘备   | 92;82;88                          |
| 张飞   | 90;71;97                          |
+--------+-----------------------------------+
3 rows in set (0.00 sec)

接下来我们还可以对score进行排序:

mysql> select name,group_concat(score order by score desc separator ';') from student group by name;
+--------+-------------------------------------------------------+
| name   | group_concat(score order by score desc separator ';') |
+--------+-------------------------------------------------------+
| 关羽   | 94;90;89                                              |
| 刘备   | 92;88;82                                              |
| 张飞   | 97;90;71                                              |
+--------+-------------------------------------------------------+
3 rows in set (0.00 sec)

当然,我们可以拼接多个字段:

mysql> select name,group_concat(course,score) from student group by name;
+--------+----------------------------+
| name   | group_concat(course,score) |
+--------+----------------------------+
| 关羽   | 语文89,数学94,英语90       |
| 刘备   | 语文92,数学82,英语88       |
| 张飞   | 语文90,数学71,英语97       |
+--------+----------------------------+
3 rows in set (0.00 sec)

当然,group_concat同样支持concat的基础的拼接操作:

mysql> select name,group_concat(course,'-',score) from student group by name;
+--------+--------------------------------+
| name   | group_concat(course,'-',score) |
+--------+--------------------------------+
| 关羽   | 语文-89,数学-94,英语-90        |
| 刘备   | 语文-92,数学-82,英语-88        |
| 张飞   | 语文-90,数学-71,英语-97        |
+--------+--------------------------------+
3 rows in set (0.00 sec)

注意:

group_concat函数返回的字符串默认有长度限制(1024),超过最大长度就会被截断。

查看默认设置的两种方式:

mysql> select @@global.group_concat_max_len;
+-------------------------------+
| @@global.group_concat_max_len |
+-------------------------------+
|                          1024 |
+-------------------------------+
1 row in set (0.00 sec)

mysql> show variables like "group_concat_max_len";
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| group_concat_max_len | 1024  |
+----------------------+-------+
1 row in set (0.00 sec)

如果要修改的话,修改对应的配置项即可,不过一般作为开发,我们是没权限修改数据库的配置的。

4. find_in_set函数

函数格式:

FIND_IN_SET(str,strlist)

比如说我们有个字符串类型的变量,在表里保存的形式是1,2,3,4,然后我们要判断我们的某个参数是否在这个字符串中,就可以使用该函数。

str:要查询的字符串;

strlist:参数以逗号进行分割,比如1,2,3,4

可以通俗的理解为将对字符串的筛选查询,转换为in的形式。

select * from table where FIND_IN_SET(id, '1,2,3,4,5');

等价于:

select * from table where id in ('1','2','3','4','5');

举个简单的例子,假如我们有一个用户表,包含角色:

mysql> select * from user_role;
+----+-----------+---------+
| id | user_name | role    |
+----+-----------+---------+
|  1 | 小红      | 1,2,3   |
|  2 | 小华      | 1,2     |
|  3 | 小明      | 2,3     |
|  4 | 小军      | 1,2,3,4 |
+----+-----------+---------+
4 rows in set (0.00 sec)

假如role字段中的1,2,3,4分别表示一种角色,那么如果我们想筛选包含某种角色的数据,那么可以通过:

mysql> select * from user_role where find_in_set('1', role);
+----+-----------+---------+
| id | user_name | role    |
+----+-----------+---------+
|  1 | 小红      | 1,2,3   |
|  2 | 小华      | 1,2     |
|  4 | 小军      | 1,2,3,4 |
+----+-----------+---------+
3 rows in set (0.00 sec)

mysql> select * from user_role where find_in_set('4', role);
+----+-----------+---------+
| id | user_name | role    |
+----+-----------+---------+
|  4 | 小军      | 1,2,3,4 |
+----+-----------+---------+
1 row in set (0.00 sec)

5. left(str, length)函数

该函数用于截取字符串指定长度的左侧部分:

  • str,要截取的字符串;
  • length,一个正整数,指定从左边返回的字符数;
  • 如果str或者length参数为null,则直接返回null;如果length为0或者负数,返回一个空字符串;如果length大于str字符串长度,返回整个str字符串;
mysql> select left('hello world', 5);
+------------------------+
| left('hello world', 5) |
+------------------------+
| hello                  |
+------------------------+
1 row in set (0.01 sec)

mysql> select left('hello world', null);
+---------------------------+
| left('hello world', null) |
+---------------------------+
| NULL                      |
+---------------------------+
1 row in set (0.00 sec)
mysql> select left('hello world', -10);
+--------------------------+
| left('hello world', -10) |
+--------------------------+
|                          |
+--------------------------+
1 row in set (0.00 sec)

mysql> select left('hello world', 100);
+--------------------------+
| left('hello world', 100) |
+--------------------------+
| hello world              |
+--------------------------+
1 row in set (0.00 sec)

6. right(str, length)函数

left方法相反,该方法用于截取字符串指定长度的右侧部分。规则和left方法差不多。

mysql> select right('hello world', 5);
+-------------------------+
| right('hello world', 5) |
+-------------------------+
| world                   |
+-------------------------+
1 row in set (0.00 sec)

7. field函数

格式:FIELD(str, str1, str2, str3,...),用于对sql结果进行指定顺序排序:

字段str按照给定字符串str1,str2,str3进行排序返回;如果str中字段值不在给定字符串中,则这部分数据将排在结果集最前面;如果这部分str值相同,则按照主键进行升序排序;

还是以student表为例:

mysql> select * from student;
+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  1 | 刘备   | 语文   | 92    |
|  2 | 关羽   | 语文   | 89    |
|  3 | 张飞   | 语文   | 90    |
|  4 | 刘备   | 数学   | 82    |
|  5 | 关羽   | 数学   | 94    |
|  6 | 张飞   | 数学   | 71    |
|  7 | 刘备   | 英语   | 88    |
|  8 | 关羽   | 英语   | 90    |
|  9 | 张飞   | 英语   | 97    |
+----+--------+--------+-------+
9 rows in set (0.00 sec)

进行排序:

mysql> select * from student order by field(course, '数学','语文') asc;
+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  7 | 刘备   | 英语   | 88    |
|  8 | 关羽   | 英语   | 90    |
|  9 | 张飞   | 英语   | 97    |
|  4 | 刘备   | 数学   | 82    |
|  5 | 关羽   | 数学   | 94    |
|  6 | 张飞   | 数学   | 71    |
|  1 | 刘备   | 语文   | 92    |
|  2 | 关羽   | 语文   | 89    |
|  3 | 张飞   | 语文   | 90    |
+----+--------+--------+-------+
9 rows in set (0.01 sec)

其他case:

mysql> select * from student order by field(course, '数学','语文','英语') asc;
+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  4 | 刘备   | 数学   | 82    |
|  5 | 关羽   | 数学   | 94    |
|  6 | 张飞   | 数学   | 71    |
|  1 | 刘备   | 语文   | 92    |
|  2 | 关羽   | 语文   | 89    |
|  3 | 张飞   | 语文   | 90    |
|  7 | 刘备   | 英语   | 88    |
|  8 | 关羽   | 英语   | 90    |
|  9 | 张飞   | 英语   | 97    |
+----+--------+--------+-------+
9 rows in set (0.00 sec)

降序时需要注意下:

降序时,按照str3,str2,str1的顺序逆向排序,不在给定字符串列表中的数据排到最后;相同的默认按照主键进行升序排序;

mysql> select * from student order by field(course, '语文','英语') desc;
+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  7 | 刘备   | 英语   | 88    |
|  8 | 关羽   | 英语   | 90    |
|  9 | 张飞   | 英语   | 97    |
|  1 | 刘备   | 语文   | 92    |
|  2 | 关羽   | 语文   | 89    |
|  3 | 张飞   | 语文   | 90    |
|  4 | 刘备   | 数学   | 82    |
|  5 | 关羽   | 数学   | 94    |
|  6 | 张飞   | 数学   | 71    |
+----+--------+--------+-------+
9 rows in set (0.00 sec)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342