前言
兜兜轉(zhuǎn)轉(zhuǎn),因為各種各樣的事情,已經(jīng)一年多沒有更新博客了,雖然一年過去了,但技術(shù)依舊很菜,菜就要多努力,所以還是那句話:腳踏實地,不急不躁,不以物喜,不以己悲,接著學(xué)習(xí)吧。
測試使用的mysql版本:5.7.20。
- 本文所涉及到的函數(shù)包括concat,concat_ws,group_concat,find_in_set,left,right,field等。
1. concat(str1,str2,...)函數(shù)
相比大家應(yīng)該都使用過concat()函數(shù)吧,用來連接多個字符串,該方法比較簡單:
mysql> select concat('a','-','b','-','c');
+-----------------------------+
| concat('a','-','b','-','c') |
+-----------------------------+
| a-b-c |
+-----------------------------+
1 row in set (0.00 sec)
不過,需要注意的是,如果參數(shù)有一個為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...)函數(shù)
該方法和concat有些相似,用于連接多個字符串,不過該參數(shù)用于指定字符串連接參數(shù)之間的分隔符;也就是說,當(dāng)我們使用concat時,如果連接的參數(shù)比較多,并且連接的符號都是一樣的,可以使用該函數(shù)。
其中,第一個參數(shù)表示分隔符。
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值進(jìn)行連接到字符串中:
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函數(shù)
函數(shù)格式:
group_concat([DISTINCT] 字段1,字段2 [order by 排序字段] [separator '分隔符'])
將查詢結(jié)果中的值連接起來,默認(rèn)使用逗號作為分隔符,然后返回一個字符串結(jié)果;如果有g(shù)roup by操作,就表示將同一個分組中的值連接起來,也就是分組后相同行組合。
備注:
- 通過使用distinct可以排除重復(fù)值;如果希望對結(jié)果中的值進(jìn)行排序,可以使用order by子句;separator是一個字符串值,缺省為一個逗號;
- 在有g(shù)roup by的查詢語句中,select指定的字段要么就包含在group by語句的后面,作為分組的依據(jù),要么就包含在聚合函數(shù)中(max, min, avg, sum, count);
以下簡單舉個例子,測試數(shù)據(jù)如下:
mysql> select * from student;
+----+--------+--------+-------+
| id | name | course | score |
+----+--------+--------+-------+
| 1 | 劉備 | 語文 | 92 |
| 2 | 關(guān)羽 | 語文 | 89 |
| 3 | 張飛 | 語文 | 90 |
| 4 | 劉備 | 數(shù)學(xué) | 82 |
| 5 | 關(guān)羽 | 數(shù)學(xué) | 94 |
| 6 | 張飛 | 數(shù)學(xué) | 71 |
| 7 | 劉備 | 英語 | 88 |
| 8 | 關(guān)羽 | 英語 | 90 |
| 9 | 張飛 | 英語 | 97 |
+----+--------+--------+-------+
我們以name分組,把name相同的打印在同一行,以逗號分隔;
mysql> select name,group_concat(score) from student group by name;
+--------+---------------------+
| name | group_concat(score) |
+--------+---------------------+
| 關(guān)羽 | 89,94,90 |
| 劉備 | 92,82,88 |
| 張飛 | 90,71,97 |
+--------+---------------------+
3 rows in set (0.00 sec)
可以看到,根據(jù)name進(jìn)行分組后的score,已經(jīng)通過逗號連接在一起;如果我們不想使用逗號進(jìn)行分割,比如想使用分號進(jìn)行分割:
mysql> select name,group_concat(score separator ';') from student group by name;
+--------+-----------------------------------+
| name | group_concat(score separator ';') |
+--------+-----------------------------------+
| 關(guān)羽 | 89;94;90 |
| 劉備 | 92;82;88 |
| 張飛 | 90;71;97 |
+--------+-----------------------------------+
3 rows in set (0.00 sec)
接下來我們還可以對score進(jìn)行排序:
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 ';') |
+--------+-------------------------------------------------------+
| 關(guān)羽 | 94;90;89 |
| 劉備 | 92;88;82 |
| 張飛 | 97;90;71 |
+--------+-------------------------------------------------------+
3 rows in set (0.00 sec)
當(dāng)然,我們可以拼接多個字段:
mysql> select name,group_concat(course,score) from student group by name;
+--------+----------------------------+
| name | group_concat(course,score) |
+--------+----------------------------+
| 關(guān)羽 | 語文89,數(shù)學(xué)94,英語90 |
| 劉備 | 語文92,數(shù)學(xué)82,英語88 |
| 張飛 | 語文90,數(shù)學(xué)71,英語97 |
+--------+----------------------------+
3 rows in set (0.00 sec)
當(dāng)然,group_concat同樣支持concat的基礎(chǔ)的拼接操作:
mysql> select name,group_concat(course,'-',score) from student group by name;
+--------+--------------------------------+
| name | group_concat(course,'-',score) |
+--------+--------------------------------+
| 關(guān)羽 | 語文-89,數(shù)學(xué)-94,英語-90 |
| 劉備 | 語文-92,數(shù)學(xué)-82,英語-88 |
| 張飛 | 語文-90,數(shù)學(xué)-71,英語-97 |
+--------+--------------------------------+
3 rows in set (0.00 sec)
注意:
group_concat函數(shù)返回的字符串默認(rèn)有長度限制(1024),超過最大長度就會被截斷。
查看默認(rèn)設(shè)置的兩種方式:
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)
如果要修改的話,修改對應(yīng)的配置項即可,不過一般作為開發(fā),我們是沒權(quán)限修改數(shù)據(jù)庫的配置的。
4. find_in_set函數(shù)
函數(shù)格式:
FIND_IN_SET(str,strlist)
比如說我們有個字符串類型的變量,在表里保存的形式是1,2,3,4,然后我們要判斷我們的某個參數(shù)是否在這個字符串中,就可以使用該函數(shù)。
str:要查詢的字符串;
strlist:參數(shù)以逗號進(jìn)行分割,比如
1,2,3,4;
可以通俗的理解為將對字符串的篩選查詢,轉(zhuǎn)換為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分別表示一種角色,那么如果我們想篩選包含某種角色的數(shù)據(jù),那么可以通過:
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)函數(shù)
該函數(shù)用于截取字符串指定長度的左側(cè)部分:
- str,要截取的字符串;
- length,一個正整數(shù),指定從左邊返回的字符數(shù);
- 如果str或者length參數(shù)為null,則直接返回null;如果length為0或者負(fù)數(shù),返回一個空字符串;如果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)函數(shù)
和left方法相反,該方法用于截取字符串指定長度的右側(cè)部分。規(guī)則和left方法差不多。
mysql> select right('hello world', 5);
+-------------------------+
| right('hello world', 5) |
+-------------------------+
| world |
+-------------------------+
1 row in set (0.00 sec)
7. field函數(shù)
格式:FIELD(str, str1, str2, str3,...),用于對sql結(jié)果進(jìn)行指定順序排序:
字段str按照給定字符串str1,str2,str3進(jìn)行排序返回;如果str中字段值不在給定字符串中,則這部分?jǐn)?shù)據(jù)將排在結(jié)果集最前面;如果這部分str值相同,則按照主鍵進(jìn)行升序排序;
還是以student表為例:
mysql> select * from student;
+----+--------+--------+-------+
| id | name | course | score |
+----+--------+--------+-------+
| 1 | 劉備 | 語文 | 92 |
| 2 | 關(guān)羽 | 語文 | 89 |
| 3 | 張飛 | 語文 | 90 |
| 4 | 劉備 | 數(shù)學(xué) | 82 |
| 5 | 關(guān)羽 | 數(shù)學(xué) | 94 |
| 6 | 張飛 | 數(shù)學(xué) | 71 |
| 7 | 劉備 | 英語 | 88 |
| 8 | 關(guān)羽 | 英語 | 90 |
| 9 | 張飛 | 英語 | 97 |
+----+--------+--------+-------+
9 rows in set (0.00 sec)
進(jìn)行排序:
mysql> select * from student order by field(course, '數(shù)學(xué)','語文') asc;
+----+--------+--------+-------+
| id | name | course | score |
+----+--------+--------+-------+
| 7 | 劉備 | 英語 | 88 |
| 8 | 關(guān)羽 | 英語 | 90 |
| 9 | 張飛 | 英語 | 97 |
| 4 | 劉備 | 數(shù)學(xué) | 82 |
| 5 | 關(guān)羽 | 數(shù)學(xué) | 94 |
| 6 | 張飛 | 數(shù)學(xué) | 71 |
| 1 | 劉備 | 語文 | 92 |
| 2 | 關(guān)羽 | 語文 | 89 |
| 3 | 張飛 | 語文 | 90 |
+----+--------+--------+-------+
9 rows in set (0.01 sec)
其他case:
mysql> select * from student order by field(course, '數(shù)學(xué)','語文','英語') asc;
+----+--------+--------+-------+
| id | name | course | score |
+----+--------+--------+-------+
| 4 | 劉備 | 數(shù)學(xué) | 82 |
| 5 | 關(guān)羽 | 數(shù)學(xué) | 94 |
| 6 | 張飛 | 數(shù)學(xué) | 71 |
| 1 | 劉備 | 語文 | 92 |
| 2 | 關(guān)羽 | 語文 | 89 |
| 3 | 張飛 | 語文 | 90 |
| 7 | 劉備 | 英語 | 88 |
| 8 | 關(guān)羽 | 英語 | 90 |
| 9 | 張飛 | 英語 | 97 |
+----+--------+--------+-------+
9 rows in set (0.00 sec)
降序時需要注意下:
降序時,按照str3,str2,str1的順序逆向排序,不在給定字符串列表中的數(shù)據(jù)排到最后;相同的默認(rèn)按照主鍵進(jìn)行升序排序;
mysql> select * from student order by field(course, '語文','英語') desc;
+----+--------+--------+-------+
| id | name | course | score |
+----+--------+--------+-------+
| 7 | 劉備 | 英語 | 88 |
| 8 | 關(guān)羽 | 英語 | 90 |
| 9 | 張飛 | 英語 | 97 |
| 1 | 劉備 | 語文 | 92 |
| 2 | 關(guān)羽 | 語文 | 89 |
| 3 | 張飛 | 語文 | 90 |
| 4 | 劉備 | 數(shù)學(xué) | 82 |
| 5 | 關(guān)羽 | 數(shù)學(xué) | 94 |
| 6 | 張飛 | 數(shù)學(xué) | 71 |
+----+--------+--------+-------+
9 rows in set (0.00 sec)