深入浅出MySQL-04-【常用函数】

文章目录

前言

环境:

  • Window11
  • MySQL-8.0.35

1.字符串函数

最常用的一种函数。

注意:在 MySQL 中,字符串的下标(或称为索引)是从 1 开始的,而不是从 0 开始。

函数 功能
CONCAT(s1, s2, ..., sn) 连接s1, s2, ..., sn 为一个字符串
INSERT(str, x, y, instr) 将字符串str从第x位置开始,y个字符长的子串替换为字符串instr
LOWER(str) 将字符串str中的所有字符转换为小写
UPPER(str) 将字符串str中的所有字符转换为大写
LEFT(str, x) 返回字符串str最左边的x个字符
RIGHT(str, x) 返回字符串str最右边的x个字符
LPAD(str, n, pad) 用字符串pad对str最左边进行填充,直到长度为n个字符长度
RPAD(str, n, pad) 用字符串pad对str最右边进行填充,直到长度为n个字符长度
LTRIM(str) 去掉字符串str左侧的空格
RTRIM(str) 去掉字符串str右侧的空格
REPEAT(str, x) 返回str重复x次的结果
REPLACE(str, a, b) 用字符串b替换字符串str中所有出现的字符串a
STRCMP(s1, s2) 比较字符串s1和s2
TRIM(str) 去掉字符串行尾和行头的空格
SUBSTRING(str, x, y) 返回从字符串str的x位置起y个字符长度的字符串
  • CONCAT(s1, s2, ..., sn)函数,把传入的字符串连接成为一个字符串。但是如果其中有NULL,结果就是NULL,因为任何字符串和NULL进行连接的结果都是NULL。
sql 复制代码
mysql> select concat('aa','bb','cc'), concat('aa','bb', null);
+------------------------+-------------------------+
| concat('aa','bb','cc') | concat('aa','bb', null) |
+------------------------+-------------------------+
| aabbcc                 | NULL                    |
+------------------------+-------------------------+
1 row in set (0.01 sec)
  • INSERT(str, x, y, instr)函数,将字符串str从第x位置开始,y个字符长的字串替换为字符串instr。
sql 复制代码
// 第6个位置也就是 H 开始,5个字符的长度 Hello 替换为 MySQL
mysql> select insert('12345Hello', 6, 5, 'MySQL');
+-------------------------------------+
| insert('12345Hello', 6, 5, 'MySQL') |
+-------------------------------------+
| 12345MySQL                          |
+-------------------------------------+
1 row in set (0.01 sec)
  • LOWER(str) 和 UPPER(str)函数,把字符串转换为小写或者大写。
sql 复制代码
mysql> select lower('我是大写转小写ABC'), upper('我是小写转大写abc');
+----------------------------+----------------------------+
| lower('我是大写转小写ABC') | upper('我是小写转大写abc') |
+----------------------------+----------------------------+
| 我是大写转小写abc          | 我是小写转大写ABC          |
+----------------------------+----------------------------+
1 row in set (0.00 sec)
  • LEFT(str, x) 和 RIGTH(str, x)函数,分别是返回字符串最左边的x字符和最右边的x个字符,如果第二个参数为NULL,那么将不返回任何字符串,返回NULL。
sql 复制代码
mysql> select left('abcdef', 5), right('abcdef', 5), left('abcdef', null);
+-------------------+--------------------+----------------------+
| left('abcdef', 5) | right('abcdef', 5) | left('abcdef', null) |
+-------------------+--------------------+----------------------+
| abcde             | bcdef              | NULL                 |
+-------------------+--------------------+----------------------+
1 row in set (0.01 sec)
  • LPAD(str, n, pad) 和 RPAD(str, n, pad)函数,分别用字符串pad 对 str 最左边和最右边进行填充,直到长度为n个字符长度。
sql 复制代码
mysql> select lpad('abc', 5, 00), lpad('abc', 5, 'hellomysql'), rpad('abc', 5, 0), rpad('abc', 5, 'hellomysql');
+--------------------+------------------------------+-------------------+------------------------------+
| lpad('abc', 5, 00) | lpad('abc', 5, 'hellomysql') | rpad('abc', 5, 0) | rpad('abc', 5, 'hellomysql') |
+--------------------+------------------------------+-------------------+------------------------------+
| 00abc              | heabc                        | abc00             | abche                        |
+--------------------+------------------------------+-------------------+------------------------------+
1 row in set (0.01 sec)
  • LTRIM(str) 和 RTRIM(str)函数,分别去掉字符串str左侧和右侧的空格。
sql 复制代码
mysql> select ltrim('   |abc|   '), rtrim('   |abc|   ');
+----------------------+----------------------+
| ltrim('   |abc|   ') | rtrim('   |abc|   ') |
+----------------------+----------------------+
| |abc|                |    |abc|             |
+----------------------+----------------------+
1 row in set (0.00 sec)
  • REPEAT(str, x)函数,返回str重复x次的结果。
sql 复制代码
mysql> select repeat('HelloMySQL==', 5);
+--------------------------------------------------------------+
| repeat('HelloMySQL==', 5)                                    |
+--------------------------------------------------------------+
| HelloMySQL==HelloMySQL==HelloMySQL==HelloMySQL==HelloMySQL== |
+--------------------------------------------------------------+
1 row in set (0.00 sec)
  • REPLACE(str, a, b)函数,用字符串b替换字符串str中所有出现的字符串a。
sql 复制代码
mysql> select replace('abbaaccaaadd', 'a', '==');
+------------------------------------+
| replace('abbaaccaaadd', 'a', '==') |
+------------------------------------+
| ==bb====cc======dd                 |
+------------------------------------+
1 row in set (0.00 sec)
  • STRCMP(s1, s2)函数,比较字符串s1和s2的ASCII码值的大小,如果s1<s2,返回-1。如果s1=s2,返回0。如果s1>s2,返回1.
sql 复制代码
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 (0.01 sec)
  • SUBSTRING(str, x, y)函数,返回从字符串str中的第x位置起y个字符长度的字符串。
sql 复制代码
mysql> select substring('abcdefg', '2', 5), substring('你好我是张三', 3, 4);
+------------------------------+---------------------------------+
| substring('abcdefg', '2', 5) | substring('你好我是张三', 3, 4) |
+------------------------------+---------------------------------+
| bcdef                        | 我是张三                        |
+------------------------------+---------------------------------+
1 row in set (0.00 sec)

2.数值函数

处理数值方面的运算。

函数 功能
ABS(x) 返回x的绝对值
CEIL(x) 返回大于x的最小整数值
FLOOR(x) 返回小于x的最大整数值
MOD(x, y) 返回x/y的模, 等价于前面运算符章节中的%
RAND() 返回0~1内的随机值
ROUND(x, y) 返回参数x的四舍五入的有y位小数的值
TRUNCATE(x, y) 返回数字x截断为y位小数的结果
  • ABS(x)函数,返回x的绝对值。
sql 复制代码
mysql> select abs(0.8), abs(-0.8);
+----------+-----------+
| abs(0.8) | abs(-0.8) |
+----------+-----------+
|      0.8 |       0.8 |
+----------+-----------+
1 row in set (0.00 sec)
  • CEIL(x)函数,返回大于x的最小整数值。
sql 复制代码
mysql> select ceil(-0.8), ceil(-1.5), ceil(0.8), ceil(1.5);
+------------+------------+-----------+-----------+
| ceil(-0.8) | ceil(-1.5) | ceil(0.8) | ceil(1.5) |
+------------+------------+-----------+-----------+
|          0 |         -1 |         1 |         2 |
+------------+------------+-----------+-----------+
1 row in set (0.01 sec)
  • FLOOR(x)函数,返回小于x的最大整数值。和上面的CEIL正好相反。
sql 复制代码
mysql> select floor(-0.8), floor(-1.5), floor(0.8), floor(1.5);
+-------------+-------------+------------+------------+
| floor(-0.8) | floor(-1.5) | floor(0.8) | floor(1.5) |
+-------------+-------------+------------+------------+
|          -1 |          -2 |          0 |          1 |
+-------------+-------------+------------+------------+
1 row in set (0.00 sec)
  • MOD(x, y)函数,返回 x/y 的模,等价于前面符号章节的%操作。x和y的值任何一个为NULL,结果就是NULL。
sql 复制代码
mysql> select 10%3, 10%null, 10 mod 3, mod(10,3), mod(null, 3);
+------+---------+----------+-----------+--------------+
| 10%3 | 10%null | 10 mod 3 | mod(10,3) | mod(null, 3) |
+------+---------+----------+-----------+--------------+
|    1 |    NULL |        1 |         1 |         NULL |
+------+---------+----------+-----------+--------------+
1 row in set (0.00 sec)
  • RAND()函数,返回0~1的随机值。
sql 复制代码
mysql> select rand(), rand(), rand();
+--------------------+--------------------+--------------------+
| rand()             | rand()             | rand()             |
+--------------------+--------------------+--------------------+
| 0.5018647653068088 | 0.8444691345509786 | 0.7167514075681115 |
+--------------------+--------------------+--------------------+
1 row in set (0.00 sec)

RAND函数可以取任意指定范围内的随机数,例如需要0~100之间的任意随机整数,可以如下操作:

sql 复制代码
mysql> select ceil(rand()*100), ceil(rand()*100),  ceil(rand()*100);
+------------------+------------------+------------------+
| ceil(rand()*100) | ceil(rand()*100) | ceil(rand()*100) |
+------------------+------------------+------------------+
|                6 |               11 |               36 |
+------------------+------------------+------------------+
1 row in set (0.00 sec)
  • ROUND(x, y)函数,返回参数x的四舍五入的有y位小数的值。如果是整数,将会保留y位数量的0。如果不写y,则默认y就是0,也就是将四舍五入后取整。
sql 复制代码
mysql> select round(1.456, 2), round(1.456), round(1.456, 4), round(1), round(1.456, 0), round(1,3);
+-----------------+--------------+-----------------+----------+-----------------+------------+
| round(1.456, 2) | round(1.456) | round(1.456, 4) | round(1) | round(1.456, 0) | round(1,3) |
+-----------------+--------------+-----------------+----------+-----------------+------------+
|            1.46 |            1 |           1.456 |        1 |               1 |          1 |
+-----------------+--------------+-----------------+----------+-----------------+------------+
1 row in set (0.00 sec)
  • TRUNCATE(x, y)函数,返回数字x截断为y位小数的结果。注意和上面ROUND的区别,这里是截断不进行四舍五入操作。
sql 复制代码
mysql> select truncate(1.456, 2), truncate(1.456, 4), truncate(1, 2);
+--------------------+--------------------+----------------+
| truncate(1.456, 2) | truncate(1.456, 4) | truncate(1, 2) |
+--------------------+--------------------+----------------+
|               1.45 |              1.456 |              1 |
+--------------------+--------------------+----------------+
1 row in set (0.00 sec)

3.日期和时间函数

常用的日期函数如下:

函数 功能
CURDATE() 返回当前日期
CURTIME() 返回当前时间
NOW() 返回当前日期和时间
UNIX_TIMESTAMP(date) 返回日期date的UNIX时间戳
FROM_UNIXTIME 返回UNIX时间戳的日期值
WEEK(date) 返回日期date为一年中的第几周
YEAR(date) 返回日期date的年份
HOUR(time) 返回时间time的小时值
MINUTE(time) 返回时间time的分钟值
MONTH(date) 返回日期date为一年中的第几个月
MONTHNAME(date) 返回日期date的月份名
DATE_FORMAT(date, fmt) 返回按照字符串fmt格式化日期date后的值
DATE_ADD(date, INTERVAL expr type) 返回一个日期或时间值加上一个时间间隔的时间值
DATEDIFF(expr, expr2) 返回起始时间expr和结束日期expr2之间的天数
  • CURDATE()函数,返回当前日期,只包含 年、月、日。
  • CURTIME()函数,返回当前时间,只包含 时、分、秒。
  • NOW()函数,返回当前日期和时间,年、月、日、时、分、秒都包含。
sql 复制代码
mysql> select curdate(), curtime(), now();
+------------+-----------+---------------------+
| curdate()  | curtime() | now()               |
+------------+-----------+---------------------+
| 2024-04-24 | 16:00:26  | 2024-04-24 16:00:26 |
+------------+-----------+---------------------+
1 row in set (0.01 sec)
  • UNIX_TIMESTAMP(date)函数,返回日期date的UNIX时间戳。
sql 复制代码
mysql> select unix_timestamp(now());
+-----------------------+
| unix_timestamp(now()) |
+-----------------------+
|            1713946688 |
+-----------------------+
1 row in set (0.01 sec)
  • FROM_UNIXTIME(unixtime)函数,返回UNIXTIME时间戳的日期值,和上面的UNIX_TIMESTAMP(date)函数互为逆操作。
sql 复制代码
mysql> select unix_timestamp(now()), now();
+-----------------------+---------------------+
| unix_timestamp(now()) | now()               |
+-----------------------+---------------------+
|            1713946819 | 2024-04-24 16:20:19 |
+-----------------------+---------------------+
1 row in set (0.00 sec)

// 对比上面unix_timestamp的值,互为逆操作
mysql> select from_unixtime(1713946819);
+---------------------------+
| from_unixtime(1713946819) |
+---------------------------+
| 2024-04-24 16:20:19       |
+---------------------------+
1 row in set (0.00 sec)
  • WEEK(date) 和 YEAR(date)函数,分别返回参数date是一年中的第几周 和 哪一年。
sql 复制代码
mysql> select week(now()), year(now());
+-------------+-------------+
| week(now()) | year(now()) |
+-------------+-------------+
|          16 |        2024 |
+-------------+-------------+
1 row in set (0.00 sec)
  • HOUR(time) 和 MINUTE(time)函数,分别返回参数time的小时 和 分钟。
sql 复制代码
mysql> select now(), hour(now()), minute(now());
+---------------------+-------------+---------------+
| now()               | hour(now()) | minute(now()) |
+---------------------+-------------+---------------+
| 2024-04-24 16:23:27 |          16 |            23 |
+---------------------+-------------+---------------+
1 row in set (0.01 sec)
  • MONTHNAME(date)函数,返回参数date的英文月份名称。
  • MONTH(date)函数,返回参数date为一年中的第几个月。
sql 复制代码
mysql> select now(), monthname(now()), month(now());
+---------------------+------------------+--------------+
| now()               | monthname(now()) | month(now()) |
+---------------------+------------------+--------------+
| 2024-04-24 16:25:18 | April            |            4 |
+---------------------+------------------+--------------+
1 row in set (0.00 sec)
  • DATE_FORMAT(date, fmt)函数,按照字符串fmt格式化日期date,fmt的格式符如下:
    • %Y:四位数的年份
    • %y:两位数的年份
    • %m:两位数的月份(01-12)
    • %c:月份(1-12)
    • %d:两位数的日(01-31)
    • %e:日(1-31)
    • %H:两位数的小时(00-23)
    • %h 或 %I:两位数的小时(01-12)
    • %i:两位数的分钟(00-59)
    • %s:两位数的秒(00-59)
    • %p:AM 或 PM
    • %r:时间,12 小时制(hh:mm:ss AM 或 PM)
    • %T 或 %X:时间,24 小时制(hh:mm:ss)
    • %k:小时(0-23)
    • %l:小时(1-12)
    • %W:星期几的完整名称(例如:Sunday)
    • %a:星期几的缩写(例如:Sun)
    • %j:一年的第几天(001-366)
    • %U:周数(星期天为一周的开始,00-53)
    • %u:周数(星期一为一周的开始,00-53)
    • %V:周数(星期天为一周的开始,但第一周至少要有 4 天在这一年中,1-53)
    • %v:周数(星期一为一周的开始,但第一周至少要有 4 天在这一年中,1-53)
    • %D:美国格式的日期(月/日/年)
    • %F:年-月-日格式的日期(YYYY-MM-DD)
sql 复制代码
mysql> select date_format(now(), '%Y-%m-%d %H:%i:%s'),date_format(now(), '%Y/%m/%d %H-%i-%s');
+-----------------------------------------+-----------------------------------------+
| date_format(now(), '%Y-%m-%d %H:%i:%s') | date_format(now(), '%Y/%m/%d %H-%i-%s') |
+-----------------------------------------+-----------------------------------------+
| 2024-04-24 16:31:36                     | 2024/04/24 16-31-36                     |
+-----------------------------------------+-----------------------------------------+
1 row in set (0.00 sec)
  • DATE_ADD(date, INTERVAL expr type)函数,用于向日期值添加指定的时间间隔,INTERVAL是间隔类型的关键字,expr是表达式,要添加的时间间隔的数量或值,type表示间隔类型,如下:
expr间隔类型 描述 格式
HOUR 小时 hh
MINUTE mm
SECOND ss
YEAR YY
MONTH MM
DAY DD
YEAR_MONTH 年和月 YY-MM
DAY_HOUR 日和小时 DD hh
DAY_MINUTE 日和分钟 DD hh:mm
DAY_SECOND 日和秒 DD hh:mm:ss
HOUR_MINUTE 小时和分 hh:mm
HOUR_SECOND 小时和秒 hh:ss
MINUTE_SECOND 分钟和秒 mm:ss
sql 复制代码
// -1 day 可以用来表示减去日给定的日期
mysql> select now(), date_add(now(), interval 30 day), date_add(now(), interval 1 month), date_add(now(), interval -1 day);
+---------------------+----------------------------------+-----------------------------------+----------------------------------+
| now()               | date_add(now(), interval 30 day) | date_add(now(), interval 1 month) | date_add(now(), interval -1 day) |
+---------------------+----------------------------------+-----------------------------------+----------------------------------+
| 2024-04-24 16:42:58 | 2024-05-24 16:42:58              | 2024-05-24 16:42:58               | 2024-04-23 16:42:58              |
+---------------------+----------------------------------+-----------------------------------+----------------------------------+
1 row in set (0.01 sec)
  • DATEDIFF(date1, date2)函数,用来计算两个日期之间相差的天数。date1 - date2的,所以可能出现负数的差值,如下。
sql 复制代码
mysql> select datediff('2024-04-20',now()), now(), datediff(now(), '2024-04-20');
+------------------------------+---------------------+-------------------------------+
| datediff('2024-04-20',now()) | now()               | datediff(now(), '2024-04-20') |
+------------------------------+---------------------+-------------------------------+
|                           -4 | 2024-04-24 16:45:34 |                             4 |
+------------------------------+---------------------+-------------------------------+
1 row in set (0.00 sec)

4.流程函数

这类函数可以在SQL中实现条件选择,如下:

函数 功能
IF(value, t, f) 如果value是真,返回t,否则返回f
IFNULL(value1, value2) 如果value1不为空,返回value1,否则返回value2
CASE WHEN [expr] THEN [result] ... ELSE [default] END 如果expr表达式是真,返回result,否则返回default
CASE [expr] WHEN [value] THEN [result] ... ELSE [default] END 如果expr等于value1,返回result,否则返回default

这里测试示例我们模拟人员表的年龄进行分类,先创建一个person表,并插入一些数据,如下:

sql 复制代码
// 主键自增
mysql> create table person (
    -> id int primary key auto_increment,
    -> age int
    -> );
Query OK, 0 rows affected (0.02 sec)

// 插入年龄数据
mysql> insert into person (age) values (10),(18),(20),(30),(50),(70),(90),(100),(null);
Query OK, 9 rows affected (0.01 sec)
Records: 9  Duplicates: 0  Warnings: 0
  • IF(value, t, f)函数,这里认为年龄在60以上的属于高龄,用 "老人" 表示,而60以下的属于年轻人, 用"年轻人"表示。
sql 复制代码
mysql> select id, age, if(age>60, '老人', '年轻人') as info from person;
+----+------+--------+
| id | age  | info   |
+----+------+--------+
|  1 |   10 | 年轻人 |
|  2 |   18 | 年轻人 |
|  3 |   20 | 年轻人 |
|  4 |   30 | 年轻人 |
|  5 |   50 | 年轻人 |
|  6 |   70 | 老人   |
|  7 |   90 | 老人   |
|  8 |  100 | 老人   |
|  9 | NULL | 年轻人 |
+----+------+--------+
9 rows in set (0.00 sec)
  • IFNULL(value1, value2)函数,这个函数一般用来替换NULL值,NULL值是不能参与数值运算的,举例替换NULL值为0,如下
sql 复制代码
// id = 9的那条数据,ifnull替换为了0
mysql> select id, age, ifnull(age, 0) from person;
+----+------+----------------+
| id | age  | ifnull(age, 0) |
+----+------+----------------+
|  1 |   10 |             10 |
|  2 |   18 |             18 |
|  3 |   20 |             20 |
|  4 |   30 |             30 |
|  5 |   50 |             50 |
|  6 |   70 |             70 |
|  7 |   90 |             90 |
|  8 |  100 |            100 |
|  9 | NULL |              0 |
+----+------+----------------+
9 rows in set (0.00 sec)
  • CASE WHEN [expr] THEN [result] ... ELSE [default] END 函数,允许根据一个或多个条件返回不同的值,它的基本完整语法如下:
sql 复制代码
CASE   
    WHEN condition1 THEN result1  
    WHEN condition2 THEN result2  
    ...  
    ELSE resultN  
END
- condition1, condition2, ... 是要评估的条件。
- result1, result2, ... 是当对应条件为真时返回的结果。
- ELSE 子句是可选的,用于当所有条件都不满足时返回的结果。
- END 关键字标志着 CASE 语句的结束。

继续使用 年龄在60以上的属于高龄,用 "老人" 表示,而60以下的属于年轻人, 用"年轻人"表示 的这个列子,如下:

sql 复制代码
// 注意 else 的使用,如果没有前面符合条件的,都是用 else 来表示
mysql> select id, age, case when age>60 then '老人' when age< 60 then '年轻人' else '=====' end from person;
+----+------+--------------------------------------------------------------------------+
| id | age  | case when age>60 then '老人' when age< 60 then '年轻人' else '=====' end |
+----+------+--------------------------------------------------------------------------+
|  1 |   10 | 年轻人                                                                   |
|  2 |   18 | 年轻人                                                                   |
|  3 |   20 | 年轻人                                                                   |
|  4 |   30 | 年轻人                                                                   |
|  5 |   50 | 年轻人                                                                   |
|  6 |   70 | 老人                                                                     |
|  7 |   90 | 老人                                                                     |
|  8 |  100 | 老人                                                                     |
|  9 | NULL | =====                                                                    |
+----+------+--------------------------------------------------------------------------+
9 rows in set (0.00 sec)
  • CASE [expr] WHEN [value] THEN [result] ... ELSE [default] END 函数,这其实是case的一个简单函数,case后面跟着列名或者列的表达式,when后面跟表达式(case后面的)所有可能的值(不是值得范围,是具体等于的值),如果相等,就返回then后面的值,如下:
sql 复制代码
mysql> select id, age, (case age when 10 then '孩子' when '20' then '年轻人' when 100 then '老者' else '===' end) as info from person;
+----+------+--------+
| id | age  | info   |
+----+------+--------+
|  1 |   10 | 孩子   |
|  2 |   18 | ===    |
|  3 |   20 | 年轻人 |
|  4 |   30 | ===    |
|  5 |   50 | ===    |
|  6 |   70 | ===    |
|  7 |   90 | ===    |
|  8 |  100 | 老者   |
|  9 | NULL | ===    |
+----+------+--------+
9 rows in set (0.00 sec)

5.JSON函数

在前面深入浅出MySQL-02-【MySQL支持的数据类型】中说明过MySQL的JSON数据类型,对于JSON函数的操作,也就是各种查询、修改等,在这里说明。

函数类型 函数 功能
创建JSON JSON_ARRAY() 创建JSON数组
创建JSON JSON_OBJECT() 创建JSON对象
创建JSON JSON_QUOTE() JSON_UNQUOTE() 加上/去掉JSON文档两边的双引号
查询JSON JSON_CONTAINS() 查询文档中是否包含指定的元素
查询JSON JSON_CONTAINS_PATH() 查询文档中是否包含指定的路径
查询JSON JSON_EXTRACT() -> ->> 根据条件提取文档中的数据
查询JSON JSON_KEYS() 提取所有key的集合
查询JSON JSON_SEARCH() 返回所有符合条件的路径集合
修改JSON JSON_MERGE(废弃于版本5.7.22) JSON_MERGE_PRESERVE() 将两个文档合并
修改JSON JSON_ARRAY_APPEND() 数组尾部追加元素
修改JSON JSON_ARRAY_INSERT() 在数组的指定位置插入元素
修改JSON JSON_REMOVE() 删除文档中指定位置的元素
修改JSON JSON_REPLACE() 替换文档中指定位置的元素
修改JSON JSON_SET() 给文档中指定位置的元素设置新值,如果元素不存在,就进行插入
查询JSON元数据 JSON_DEPTH() JSON文档的深度(元素的最大嵌套层数)
查询JSON元数据 JSON_LENGTH() JSON文档的长度(元素个数)
查询JSON元数据 JSON_TYPE() JSON文档类型(数组、对象、标量类型等)
查询JSON元数据 JSON_VAILD() JSON格式是否合法
其他函数 JSON_PRETTY() 美化JSON格式
其他函数 JSON_STORAGE_SIZE() JSON文档占用的存储空间
其他函数 JSON_STORAGE_FREE() JSON文档更新操作后剩余的空间,MySQL8.0新增
其他函数 JSON_TABLE() 将JSON文档转换为表格,MySQL8.0新增
其他函数 JSON_ARRAYAGG() 讲聚合后参数中的多个值转换为JSON数组
其他函数 JSON_OBJECTAGG() 讲两个列或者是表达式解释为一个key和一个value,返回一个JSON对象

如上表格,JSON函数功能分为几类:

  1. 创建JSON函数
  2. 查询JSON函数
  3. 修改JSON函数
  4. 查询JSON元数据函数
  5. 其他函数

5.1.创建JSON函数

  • JSON_ARRAY(val1, val2, ..., valn)函数,返回包含参数中所有值的JSON数组,参数中的null、true、false大小写不敏感。
sql 复制代码
// 混合类型的JONS数组
mysql> select json_array(1, 'abc', "def", true, FALSE, null, NULL, now());
+--------------------------------------------------------------------------+
| json_array(1, 'abc', "def", true, FALSE, null, NULL, now())              |
+--------------------------------------------------------------------------+
| [1, "abc", "def", true, false, null, null, "2024-04-25 15:31:16.000000"] |
+--------------------------------------------------------------------------+
1 row in set (0.08 sec)
  • JSON_OBJECT(key1, value1[, key2, value2] ..., keyn, valuen)函数,返回包含参数中所有键值对的对象,参数key不能为null,参数个数也不能为奇数(键值对成双成对),否则报语法错。
sql 复制代码
mysql> select json_object('name', 'testmysql', 'age', 10);
+---------------------------------------------+
| json_object('name', 'testmysql', 'age', 10) |
+---------------------------------------------+
| {"age": 10, "name": "testmysql"}            |
+---------------------------------------------+
1 row in set (0.00 sec)
  • JSON_QUOTE(string)函数,将参数中的JSON文档转换为双引号引起来的字符串,如果文档包含双引号,则转换后的字符串自动加上转义字符"\",如下:
sql 复制代码
mysql> select json_quote("{'name','testmysql'}"), json_quote('{"name","testmysql"}'), json_quote('[1,2,3]'), json_quote('"null"');
+------------------------------------+------------------------------------+-----------------------+----------------------+
| json_quote("{'name','testmysql'}") | json_quote('{"name","testmysql"}') | json_quote('[1,2,3]') | json_quote('"null"') |
+------------------------------------+------------------------------------+-----------------------+----------------------+
| "{'name','testmysql'}"             | "{\"name\",\"testmysql\"}"         | "[1,2,3]"             | "\"null\""           |
+------------------------------------+------------------------------------+-----------------------+----------------------+
1 row in set (0.00 sec)
  • JSON_UNQUOTE(string)函数,和上面的JSON_QUOTE()函数相反。

5.2.查询JSON函数

  • JSON_CONTAINS(target, condidate, path)函数,其中第三个参数path是可选的。此函数可以查询指定的元素condidate是否包含在目标JSON文档target中,包含则返回1,否则返回0。如果参数为null或path(指定了path参数,path指向的值不存在),则返回null。

例如分别查询元素 "abc"、1、10 是否包含在JSON文档[1,2,3,"abc",null]中,如下:

sql 复制代码
mysql> select json_contains('[1,2,3,"abc",null]', '"abc"');
+----------------------------------------------+
| json_contains('[1,2,3,"abc",null]', '"abc"') |
+----------------------------------------------+
|                                            1 |
+----------------------------------------------+
1 row in set (0.00 sec)

mysql> select json_contains('[1,2,3,"abc",null]', '1');
+------------------------------------------+
| json_contains('[1,2,3,"abc",null]', '1') |
+------------------------------------------+
|                                        1 |
+------------------------------------------+
1 row in set (0.00 sec)

mysql> select json_contains('[1,2,3,"abc",null]', '10');
+-------------------------------------------+
| json_contains('[1,2,3,"abc",null]', '10') |
+-------------------------------------------+
|                                         0 |
+-------------------------------------------+
1 row in set (0.00 sec)

mysql> select json_contains('[1,2,3,"abc",null]', 'null');
+---------------------------------------------+
| json_contains('[1,2,3,"abc",null]', 'null') |
+---------------------------------------------+
|                                           1 |
+---------------------------------------------+
1 row in set (0.00 sec)

mysql> select json_contains('[1,2,3,"abc",null]', null);
+-------------------------------------------+
| json_contains('[1,2,3,"abc",null]', null) |
+-------------------------------------------+
|                                      NULL |
+-------------------------------------------+
1 row in set (0.00 sec)

要查找的元素如果是数组也是可以的:

sql 复制代码
mysql> select json_contains('[1,2,3,"abc",null]', '[1,3]');
+----------------------------------------------+
| json_contains('[1,2,3,"abc",null]', '[1,3]') |
+----------------------------------------------+
|                                            1 |
+----------------------------------------------+
1 row in set (0.00 sec)

mysql> select json_contains('[1,2,3,"abc",null]', '[1,6]');
+----------------------------------------------+
| json_contains('[1,2,3,"abc",null]', '[1,6]') |
+----------------------------------------------+
|                                            0 |
+----------------------------------------------+
1 row in set (0.00 sec)

mysql> select json_contains('[1,2,3,"abc",null]', '[1,"abc"]');
+--------------------------------------------------+
| json_contains('[1,2,3,"abc",null]', '[1,"abc"]') |
+--------------------------------------------------+
|                                                1 |
+--------------------------------------------------+
1 row in set (0.00 sec)

刚才说path参数是可选的,path参数可以指定要查询的JSON文档路径(如果你懂的java中的jsonpath,那这里就明白了),例如要查询JSON文档 {"jack", 10, "tom", 20}中是否包含值为10的对象,同时指定path为$.jack(意思就是在key=jack的value条件下,判断是不是等于10)

sql 复制代码
mysql> select json_contains(json_object("jack", 10, "tom", 20), '10', '$.jack');
+-------------------------------------------------------------------+
| json_contains(json_object("jack", 10, "tom", 20), '10', '$.jack') |
+-------------------------------------------------------------------+
|                                                                 1 |
+-------------------------------------------------------------------+
1 row in set (0.01 sec)

mysql> select json_contains(json_object("jack", 10, "tom", 20), '20', '$.tom');
+------------------------------------------------------------------+
| json_contains(json_object("jack", 10, "tom", 20), '20', '$.tom') |
+------------------------------------------------------------------+
|                                                                1 |
+------------------------------------------------------------------+
1 row in set (0.00 sec)
  • JSON_EXTRACT(json_doc, path, ... path)函数,可以从JSON文档中抽取数据,如果参数有NULL或path不存在,则返回NULL。如果抽取出多个path,则返回的数据合并在一个JSON_ARRAY里。
sql 复制代码
// 取文档的第一个和第二个元素
mysql> select json_extract('[1, 2, [3, 4]]', '$[0]', '$[1]');
+------------------------------------------------+
| json_extract('[1, 2, [3, 4]]', '$[0]', '$[1]') |
+------------------------------------------------+
| [1, 2]                                         |
+------------------------------------------------+
1 row in set (0.00 sec)

// 取文档的第一个和第三个元素
mysql> select json_extract('[1, 2, [3, 4]]', '$[0]', '$[2]');
+------------------------------------------------+
| json_extract('[1, 2, [3, 4]]', '$[0]', '$[2]') |
+------------------------------------------------+
| [1, [3, 4]]                                    |
+------------------------------------------------+
1 row in set (0.00 sec)

// 取文档的第三个元素
mysql> select json_extract('[1, 2, [3, 4]]', '$[2]');
+----------------------------------------+
| json_extract('[1, 2, [3, 4]]', '$[2]') |
+----------------------------------------+
| [3, 4]                                 |
+----------------------------------------+
1 row in set (0.00 sec)

再看一个JSON对象属性的提取,如下:

sql 复制代码
mysql> select json_extract('{"name":"test", "age":10}', '$.age');
+----------------------------------------------------+
| json_extract('{"name":"test", "age":10}', '$.age') |
+----------------------------------------------------+
| 10                                                 |
+----------------------------------------------------+
1 row in set (0.00 sec)

MySQL 5.7.9版本之后,可以用简单的函数 "->" 和 "->>"来替代 JSON_EXTRACT,但是这种写法需要从表中JOSN字段获取,因为函数的左边需要指定列名(column->path),这里就不举例了。

  • JSON_KEYS(json_doc, [path])函数,获取JSON文档在指定路径下的所有键值,返回一个JSON_ARRAY。如果有参数为NULL和path不存在,则返回NULL。
sql 复制代码
mysql> select json_keys('{"name":"test", "age":10}');
+----------------------------------------+
| json_keys('{"name":"test", "age":10}') |
+----------------------------------------+
| ["age", "name"]                        |
+----------------------------------------+
1 row in set (0.01 sec)

如果JSON文档中的元素都是ARRAY,结果也是返回NULL。

  • JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...])函数,查询包含指定字符串的路径,并作为一个JSON_ARRAY返回。如果有参数为NULL或path不存在,则返回NULL。

参数说明:

- json_doc: JSON 文档
- one_or_all: 搜索模式,可以是 'one' 或 'all'。'one' 表示返回第一个匹配的路径,'all' 表示返回所有	匹配路径的数组。
- search_str: 要搜索的字符串或 JSON 类型的值。
- escape_char: 用于转义路径中的特殊字符的字符。默认是 NULL,表示不使用转义。
- path: 可选参数,用于指定搜索的起始路径。
sql 复制代码
// 使用 json_search 来搜索 "Ford" 这个值
mysql> SELECT JSON_SEARCH('{"name": "John", "age": 30, "cars": {"car1": "Ford", "car2": "BMW", "car3": "Fiat"}}', 'one', 'Ford');
+--------------------------------------------------------------------------------------------------------------------+
| JSON_SEARCH('{"name": "John", "age": 30, "cars": {"car1": "Ford", "car2": "BMW", "car3": "Fiat"}}', 'one', 'Ford') |
+--------------------------------------------------------------------------------------------------------------------+
| "$.cars.car1"                                                                                                      |
+--------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

5.3.修改JSON的函数

  • JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)函数,可以在指定path的json array尾部追加val。如果指定path是一个json object,则将其封装成一个json array再追加。如果参数有NULL,则返回NULL。
sql 复制代码
// 追加一个值
mysql> SELECT JSON_ARRAY_APPEND('{"numbers": [1, 2]}', '$.numbers', 3);
+----------------------------------------------------------+
| JSON_ARRAY_APPEND('{"numbers": [1, 2]}', '$.numbers', 3) |
+----------------------------------------------------------+
| {"numbers": [1, 2, 3]}                                   |
+----------------------------------------------------------+
1 row in set (0.01 sec)

// 追加多个值
mysql> SELECT JSON_ARRAY_APPEND('{"numbers": [1, 2]}', '$.numbers', 3, '$.numbers', 4);
+--------------------------------------------------------------------------+
| JSON_ARRAY_APPEND('{"numbers": [1, 2]}', '$.numbers', 3, '$.numbers', 4) |
+--------------------------------------------------------------------------+
| {"numbers": [1, 2, 3, 4]}                                                |
+--------------------------------------------------------------------------+
1 row in set (0.00 sec)
  • JSON_ARRAY_INSERT(json_doc, path, val[, path, val]...)函数,可以在path指定的json array元素插入val,原位置以及以右的元素依次右移。如果path指定的数据非json array元素,则忽略此val。如果指定的元素下标超过json array的长度,则插入尾部。
sql 复制代码
// 在索引为 2 的位置(原本为 4 的位置)插入一个值 3
mysql> SELECT JSON_ARRAY_INSERT('{"numbers": [1, 2, 4]}', '$.numbers[2]', 3);
+----------------------------------------------------------------+
| JSON_ARRAY_INSERT('{"numbers": [1, 2, 4]}', '$.numbers[2]', 3) |
+----------------------------------------------------------------+
| {"numbers": [1, 2, 3, 4]}                                      |
+----------------------------------------------------------------+
1 row in set (0.00 sec)
  • JSON_REPLACE(json_doc, path, val[, path, val]...)函数,可以替换指定路径的数据,如果某个path不存在,则忽略(存在才替换)。如果有参数为NULL,则返回NULL。
sql 复制代码
// 想要替换 "age" 的值为 35,并添加一个新的键 "country",其值为 "USA"
mysql> SELECT JSON_REPLACE('{"name": "John", "age": 30, "city": "New York"}', '$.age', 35, '$.country', 'USA');
+--------------------------------------------------------------------------------------------------+
| JSON_REPLACE('{"name": "John", "age": 30, "city": "New York"}', '$.age', 35, '$.country', 'USA') |
+--------------------------------------------------------------------------------------------------+
| {"age": 35, "city": "New York", "name": "John"}                                                  |
+--------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
  • JSON_SET(json_doc, path, val[, path, val]...)函数,可以设置指定路径的数据,不管是否存在。如果参数存在NULL,则返回NULL。和上面的JSON REPLACE函数类似,最主要区别就是指定的路径存不存在。

  • JSON_MERGE_PRESERVE(json_doc, json_doc[, json_doc]...)函数,可以将多个JSON文档进行合并,合并规则如下:

      - 如果都是json array,则结果自动merge为一个json array;
      - 如果都是json object,则结果自动merge为一个json object;
      - 如果多种类型,则将非json array的元素封装为json array再按照规则一进行merge。
    
sql 复制代码
// 合并两个json文档
mysql> SELECT JSON_MERGE_PRESERVE('{"a": 1, "b": 2}', '{"b": 3, "c": 4}');
+-------------------------------------------------------------+
| JSON_MERGE_PRESERVE('{"a": 1, "b": 2}', '{"b": 3, "c": 4}') |
+-------------------------------------------------------------+
| {"a": 1, "b": [2, 3], "c": 4}                               |
+-------------------------------------------------------------+
1 row in set (0.00 sec)
  • JSON_REMOVE(json_doc,path[, path]...)函数,可以移除指定路径的数据,如果路径不存在则忽略。如果有参数为NULL,则返回NULL。
sql 复制代码
mysql> select json_remove('[1,2,3,4]', '$[1]', '$[2]');
+------------------------------------------+
| json_remove('[1,2,3,4]', '$[1]', '$[2]') |
+------------------------------------------+
| [1, 3]                                   |
+------------------------------------------+
1 row in set (0.01 sec)

仔细看,如果按照理解不是删除了第二个和第三个元素,结果不应该是 1,4 嘛,但却是1,3。因为制定了多个path,删除操作是串行的,先删除第而个元素,结果是 1,3,4。然后在此基础上在删除第三个元素,也就是结果就是 1,3 了。

5.4.查询JSON元数据函数

  • JSON_DEPTH(json_doc)函数,用来获取JSON文档的深度,如果JSON文档是空数组、空对象、null、true和false,则深度为1。如果非空数组或非空对象里面包含的都是深度为1的对象,则整个文档深度为2。以此类推,整个文档的深度取决于最大元素的深度。
sql 复制代码
mysql> select json_depth(null), json_depth('[]'), json_depth('{"name":"test"}') test1 ,json_depth('{"name":"test", "hobby":[{"name":"篮球"}]}') test2;
+------------------+------------------+-------+-------+
| json_depth(null) | json_depth('[]') | test1 | test2 |
+------------------+------------------+-------+-------+
|             NULL |                1 |     2 |     4 |
+------------------+------------------+-------+-------+
1 row in set (0.00 sec)
  • JSON_LENGTH(json_doc[, path])函数,获取指定路径下的文档长度,长度的计算规则如下:

      - 标量(字符串、数字)的长度为1
      - json array的长度为元素的个数
      - json object的长度为元素的个数
      - 嵌套数组或嵌套对象不计算长度
    
sql 复制代码
mysql> select json_length(null), json_length('123456'), json_length('[1,2,3]'), json_length('{"name":"test"}');
+-------------------+-----------------------+------------------------+--------------------------------+
| json_length(null) | json_length('123456') | json_length('[1,2,3]') | json_length('{"name":"test"}') |
+-------------------+-----------------------+------------------------+--------------------------------+
|              NULL |                     1 |                      3 |                              1 |
+-------------------+-----------------------+------------------------+--------------------------------+
1 row in set (0.00 sec)
  • JSON_TYPE(json_val)函数,获取JSON文档的类型,可以是数组、对象或标量类型。
sql 复制代码
mysql> select json_type('[1,2]'), json_type('{"name":"test"}'), json_type('1'), json_type('"hi"'), json_type(null);
+--------------------+------------------------------+----------------+-------------------+-----------------+
| json_type('[1,2]') | json_type('{"name":"test"}') | json_type('1') | json_type('"hi"') | json_type(null) |
+--------------------+------------------------------+----------------+-------------------+-----------------+
| ARRAY              | OBJECT                       | INTEGER        | STRING            | NULL            |
+--------------------+------------------------------+----------------+-------------------+-----------------+
1 row in set (0.00 sec)
  • JSON_VALID(json_val)函数,判断函数值val是否为有效的JSON格式,有效返回1,否则返回0.
sql 复制代码
mysql> select json_valid('[123'), json_valid(null), json_valid('[1,2]');
+--------------------+------------------+---------------------+
| json_valid('[123') | json_valid(null) | json_valid('[1,2]') |
+--------------------+------------------+---------------------+
|                  0 |             NULL |                   1 |
+--------------------+------------------+---------------------+
1 row in set (0.01 sec)

5.5.JSON工具函数

  • JSON_PRETTY(json_val)函数,梅花JSON的输出格式。
sql 复制代码
mysql> select json_pretty('[1,2,3]'), json_pretty('{"name":"test","age":10}');
+------------------------+-----------------------------------------+
| json_pretty('[1,2,3]') | json_pretty('{"name":"test","age":10}') |
+------------------------+-----------------------------------------+
| [
  1,
  2,
  3
]      | {
  "age": 10,
  "name": "test"
}       |
+------------------------+-----------------------------------------+
1 row in set (0.00 sec)
  • JSON_STORAGE_SIZE(json_val) / JSON_STORAGE_FREE(json_val)函数,分别获取JSON文档占用的存储空间(byte)和由于JSON_SET、JSON_REPLACE、JSON_REMOVE操作导致释放的空间。

  • JSON_TABLE(expr, path COLUMNS (column_list) [AS] alias)函数,将JSON文档映射为表格。参数expr可以是表达式或者列。path是用来过滤的JSON路径。COLUMNS是常量关键字。column list是转换后的字段列表。

这个函数可以将复杂的JSON文档转换为表格数据,转换后可以向正常表一样做链接、排序等各种操作。

  • JSON_ARRAYAGG(col_or_expr)函数,将聚合后参数中的多个值转换为JSON数组 或 将一组值转换为JSON数组。它接受一个参数,即要转换为数组的列名或表达式,并返回JSON格式的字符串。
  • JSON_OBJECTAGG(key, value)函数,将两个列或表达式解释为一个key和一个value,返回一个JSON对象。

6.窗口函数

MySQL 8.0 引入了窗口函数(Window Functions),它们允许用户执行计算跨行集(称为窗口)的操作,而不是仅针对单行。窗口函数通常与 OVER() 子句一起使用,该子句定义了窗口的范围以及窗口如何沿着结果集移动。

窗口函数非常有用,尤其是在进行如累计总和、移动平均、排名等计算时。

以下是一些常见的 MySQL 窗口函数:

  • ROW_NUMBER():为结果集中的每一行分配一个唯一的序号。
sql 复制代码
SELECT name, age, ROW_NUMBER() OVER (ORDER BY age DESC) as rank  FROM users;
  • RANK() 和 DENSE_RANK():为结果集中的每一行分配一个排名。RANK() 在遇到相同的值时会跳过下一个排名,而 DENSE_RANK() 则不会。
sql 复制代码
SELECT name, score, RANK() OVER (ORDER BY score DESC) as rank  FROM scores;
  • NTILE(n):将结果集分成大致相等的 n 个部分,并为每一行分配一个桶号。
sql 复制代码
SELECT name, score, NTILE(4) OVER (ORDER BY score DESC) as quartile  FROM scores;
  • LEAD() 和 LAG():获取结果集中当前行之前或之后的行的值。
sql 复制代码
SELECT date, sales,   
       LAG(sales) OVER (ORDER BY date) as previous_day_sales,  
       LEAD(sales) OVER (ORDER BY date) as next_day_sales  
FROM sales_data;
  • FIRST_VALUE() 和 LAST_VALUE():获取窗口范围内的第一个或最后一个值。
sql 复制代码
SELECT date, sales,   
       FIRST_VALUE(sales) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as first_sales_in_window,  
       LAST_VALUE(sales) OVER (ORDER BY date ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) as last_sales_in_window  
FROM sales_data;
  • SUM(), AVG(), MIN(), MAX() 等聚合函数也可以用作窗口函数。例如,计算累计总和:
sql 复制代码
SELECT date, sales, SUM(sales) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as cumulative_sales  
FROM sales_data;

使用窗口函数时,你可以通过 PARTITION BY 子句将数据分成多个分区,并为每个分区独立地计算窗口函数。这允许你在每个分区内进行排名、累计等计算。

请注意,为了使用窗口函数,你的 MySQL 服务器版本必须是 8.0 或更高。在早期的 MySQL 版本中,这些功能是不可用的。

7.其他函数

除了前面的函数,还有很多函数,就不一一列举了,这里说一些其他的函数。

函数 功能
DATABASE() 返回当前数据库名
VERSION() 返回当前数据库版本
USER() 返回当前登录用户名
INET_ATON(IP) 返回IP地址的数字表示
INET_NTOA(num) 返回数字代表的IP地址
PASSWORD(str) 返回字符串str的加密版本
MD5(str) 返回字符串str的MD5值
相关推荐
Hacker_LaoYi12 分钟前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀14 分钟前
Redis梳理
数据库·redis·缓存
独行soc14 分钟前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
你的微笑,乱了夏天1 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
工业甲酰苯胺1 小时前
分布式系统架构:服务容错
数据库·架构
独行soc2 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍08-基于时间延迟的SQL注入(Time-Based SQL Injection)
数据库·sql·安全·渗透测试·漏洞挖掘
White_Mountain2 小时前
在Ubuntu中配置mysql,并允许外部访问数据库
数据库·mysql·ubuntu
Code apprenticeship2 小时前
怎么利用Redis实现延时队列?
数据库·redis·缓存
百度智能云技术站2 小时前
广告投放系统成本降低 70%+,基于 Redis 容量型数据库 PegaDB 的方案设计和业务实践
数据库·redis·oracle
老王笔记2 小时前
GTID下复制问题和解决
mysql