MySQL 函数的一个小tip
今天上班的时候,同事问了一个问题,关于MySQL函数的。说实话,这方面积累确实比较少,主要原因是函数和存储过程都偏向于业务逻辑,在线上环境一般不建议使用,开发人员应该尽可能将这些业务逻辑写在业务代码里面,而不是让数据库去操作。数据库应该去做它擅长的事情,例如数据的增删改查之类的。
但是,这也不是说线上环境,就不允许使用函数和存储过程,有些存量的历史业务,可能改造起来成本过高,收益和成本不成正比,所以数据库里面还是有这些数据形态存在。
01
问题介绍
这个具体的函数问题,可以拆分为以下几个:
1、如何查看MySQL函数的详细信息?
这个问题其实还好,在MySQL5.7和MySQL8.0里面,我们都可以通过information_schema.routines和information_schema.parameters来查看函数的相关信息。
其中routines表显示的是函数的创建信息;parameters表显示的是函数的参数信息。
来看下面例子:
创建一个简单的函数:
代码语言:javascript复制mysql> create function myf1 (param1 int) returns int
mysql> no sql
mysql> begin
mysql> return (select 2);
mysql> end//
Query OK, 0 rows affected (0.02 sec)
简单解释下这个SQL吧:
param1 int代表我们的输入参数是一个整数;
returns int代表函数返回值是个整数;
no sql表示函数体不包含SQL语句;
return (select 2)是真正的函数体。
函数的创建信息:
代码语言:javascript复制mysql> select * from information_schema.routines where routine_schema='test' G
*************************** 1. row ***************************
SPECIFIC_NAME: myf1
ROUTINE_CATALOG: def
ROUTINE_SCHEMA: test
ROUTINE_NAME: myf1
ROUTINE_TYPE: FUNCTION
DATA_TYPE: int
CHARACTER_MAXIMUM_LENGTH: NULL
CHARACTER_OCTET_LENGTH: NULL
NUMERIC_PRECISION: 10
NUMERIC_SCALE: 0
DATETIME_PRECISION: NULL
CHARACTER_SET_NAME: NULL
COLLATION_NAME: NULL
DTD_IDENTIFIER: int
ROUTINE_BODY: SQL
ROUTINE_DEFINITION: begin return (select 2); end
EXTERNAL_NAME: NULL
EXTERNAL_LANGUAGE: SQL
PARAMETER_STYLE: SQL
IS_DETERMINISTIC: NO
SQL_DATA_ACCESS: NO SQL
SQL_PATH: NULL
SECURITY_TYPE: DEFINER
CREATED: 2023-01-09 06:26:05
LAST_ALTERED: 2023-01-09 06:26:05
SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
ROUTINE_COMMENT:
DEFINER: root@%
CHARACTER_SET_CLIENT: utf8mb4
COLLATION_CONNECTION: utf8mb4_0900_ai_ci
DATABASE_COLLATION: utf8mb4_0900_ai_ci
函数的参数信息:
代码语言:javascript复制mysql> select * from information_schema.parameters where specific_schema='test'G
*************************** 1. row ***************************
SPECIFIC_CATALOG: def
SPECIFIC_SCHEMA: test
SPECIFIC_NAME: myf1
ORDINAL_POSITION: 0
PARAMETER_MODE: NULL
PARAMETER_NAME: NULL
DATA_TYPE: int
CHARACTER_MAXIMUM_LENGTH: NULL
CHARACTER_OCTET_LENGTH: NULL
NUMERIC_PRECISION: 10
NUMERIC_SCALE: 0
DATETIME_PRECISION: NULL
CHARACTER_SET_NAME: NULL
COLLATION_NAME: NULL
DTD_IDENTIFIER: int
ROUTINE_TYPE: FUNCTION
*************************** 2. row ***************************
SPECIFIC_CATALOG: def
SPECIFIC_SCHEMA: test
SPECIFIC_NAME: myf1
ORDINAL_POSITION: 1
PARAMETER_MODE: IN
PARAMETER_NAME: param1
DATA_TYPE: int
CHARACTER_MAXIMUM_LENGTH: NULL
CHARACTER_OCTET_LENGTH: NULL
NUMERIC_PRECISION: 10
NUMERIC_SCALE: 0
DATETIME_PRECISION: NULL
CHARACTER_SET_NAME: NULL
COLLATION_NAME: NULL
DTD_IDENTIFIER: int
ROUTINE_TYPE: FUNCTION
注意红色的部分,就是问题所在。
第二行好理解,就是我们传入的参数param1,它的mode是IN,类型为int。
第一行包含参数名为Null的参数,它的mode也是Null,类型是int
2、为什么输入参数只有1个,单数parameter里面还有一行PARAMETER_MODE=Null,PARAMETER_NAME=Null 的记录?
这个问题当时确实比较模糊,主要是对于Null值不太清楚,查了查官方文档,找到了结果。
PARAMETER_MODE
The mode of the parameter. This value is one ofIN
,OUT
, orINOUT
. For a stored function return value, this value isNULL
.PARAMETER_NAME
The name of the parameter. For a stored function return value, this value isNULL
.DATA_TYPE
The parameter data type. TheDATA_TYPE
value is the type name only with no other information. TheDTD_IDENTIFIER
value contains the type name and possibly other information such as the precision or length.
简单翻译一下:
对于PARAMETER_MODE字段,正常取值是in,out或者inout,但是对于函数返回值,这个值是NULL;我们没有定义param1参数的取值,原因在官方文档中也有体现:
Specifying a parameter as IN
, OUT
, or INOUT
is valid only for a PROCEDURE
. For a FUNCTION
, parameters are always regarded as IN
parameters.(对于函数,参数总是被视作in类型)
对于PARAMETER_NAME字段,正常取值是参数名字,对于函数返回值,这个值是NULL;
对于DATA_TYPE字段,这个字段只返回类型名字,而不包含其他信息,例如类型长度。也就意味着如果函数返回值是varchar(10),这个字段也会只显示varchar,而没有长度信息。长度信息需要在另外一个字段DTD_IDENTIFIER上去获取。
到这里,这个小问题就解决了。相信不长使用函数的小伙伴,肯定也有收获。
最近很少搞MySQL相关的东西,抽空水一篇,今天就到这里吧。晚安。