不可不熟悉的 --MySQL高级查询语句———函数及存储过程

MySQL 数据库函数提供了能够实现各种功能的方法,使我们在查询记录时能够更高效的输出。MySQL 内建了很多函数,常用的包括数学函数、聚合函数、字符串函数和日期时间函数。

数学函数

数据库内存储的记录,经常要进行一系列的算术操作,所以 MySQL 支持很多数学函数。常用的数学函数如表
数学函数----------- 描述
abs(x) ---------------返回 x 的绝对值
rand() --------------- 返回 0 到 1 的随机数【包括0但是只能无限接近1,不包含1】
mod(x,y) ------------ 返回 x 除以 y 以后的余数
power(x,y) -----------返回 x 的 y 次方
round(x) -------------- 返回离 x 最近的整数
round(x,y) ------------保留x 的y 位小数四舍五入后的值
sqrt(x) ----------------- 返回 x 的平方根
truncate(x,y)---------- 返回数字 x 截断为 y 位小数的值
ceil(x) ------------------返回大于或等于 x 的最小整数
floor(x) ----------------- 返回小于或等于 x 的最大整数
greatest(x1,x2…) ----返回集合中最大的值
least(x1,x2…) ----------返回集合中最小的值

mysql> select abs(-1),rand(),mod(7,2),power(2,3),round(1.4),round(1.5),round(1.49);
+---------+--------------------+----------+------------+------------+------------+-------------+
| abs(-1) | rand()             | mod(7,2) | power(2,3) | round(1.4) | round(1.5) | round(1.49) |
+---------+--------------------+----------+------------+------------+------------+-------------+
|       1 | 0.3543111377901501 |        1 |          8 |          1 |          2 |           1 |
+---------+--------------------+----------+------------+------------+------------+-------------+

1 row in set (0.00 sec)
mysql> select round(1.8937,3), truncate(1.235,2), ceil(5.2), floor(2.1), least(1.89,3,6.1,2.1),greatest(4,3,2,6));
+-----------------+-------------------+-----------+------------+-----------------------+-------------------+
| round(1.8937,3) | truncate(1.235,2) | ceil(5.2) | floor(2.1) | least(1.89,3,6.1,2.1) | greatest(4,3,2,6) |
+-----------------+-------------------+-----------+------------+-----------------------+-------------------+
|           1.894 |              1.23 |         6 |          2 |                  1.89 |                 6 |
+-----------------+-------------------+-----------+------------+-----------------------+-------------------+
1 row in set (0.00 sec)

mysql> select ceil(rand()*100);  ##执行随机的0到99的整数
mysql> select mod(ceil(rand()*100),3);   ###输出随机的0到2的整数

聚合函数

MySQL 数据库函数中专门有一组函数是特意为库内记录求和或者对表中的数据进行集中概括而设计的,这些函数被称作聚合函数。常见的聚合函数
聚合函数 描述
avg()------------ 返回指定列的平均值
count() ---------返回指定列中非 NULL 值的个数
min() -----------返回指定列的最小值
max() ----------返回指定列的最大值
sum(x) ---------返回指定列的所有值之和

mysql> select count(3),count(0);
+----------+----------+
| count(3) | count(0) |
+----------+----------+
|        1 |        1 |
+----------+----------+
1 row in set (0.00 sec)
mysql> select avg(score),sum(score),max(score),min(score) from info;
+------------+------------+------------+------------+
| avg(score) | sum(score) | max(score) | min(score) |
+------------+------------+------------+------------+
|  86.125000 |     689.00 |      98.00 |      70.00 |
+------------+------------+------------+------------+
1 row in set (0.00 sec)

mysql> select score from info where 1=1 order by score desc limit 3;         ###统计成绩的前三名
+-------+
| score |
+-------+
| 98.00 |
| 95.00 |
| 90.00 |
+-------+
3 rows in set (0.00 sec)

字符串函数

常用函数不仅包括数学函数和聚合函数,还包含字符串函数,MySQL 为字符串的相关操作设计了丰富的字符串函数。常用的字符串函数如表
字符串函数 描述
length(x) ---------- 返回字符串 x 的长度
trim() --------------- 返回去除指定格式的值
concat(x,y) --------将提供的参数 x 和 y 拼接成一个字符串
upper(x) ------------将字符串 x 的所有字母变成大写字母
lower(x) -------------将字符串 x 的所有字母变成小写字母
left(x,y) -------------返回字符串 x 的前 y 个字符
right(x,y) -----------返回字符串 x 的后 y 个字符
repeat(x,y) --------- 将字符串 x 重复 y 次
space(x) ------------返回 x 个空格
replace(x,y,z) -----将字符串 z 替代字符串 x 中的字符串 y
strcmp(x,y) --------比较 x 和 y,返回的值可以为-1,0,1
substring(x,y,z) —获取从字符串 x 中的第 y 个位置开始长度为 z 的字符串
reverse(x) ---------将字符串 x 反转

mysql> select length('abc'),length(' bdc'),length(''),length('asd '),length('asa s'),length('null'),length(null);
+---------------+----------------+------------+----------------+-----------------+----------------+--------------+
| length('abc') | length(' bdc') | length('') | length('asd ') | length('asa s') | length('null') | length(null) |
+---------------+----------------+------------+----------------+-----------------+----------------+--------------+
|             3 |              4 |          0 |              4 |               5 |              4 |         NULL |
+---------------+----------------+------------+----------------+-----------------+----------------+--------------+
1 row in set (0.01 sec)

mysql> select length(trim(' abc')),length(trim('sds ')),length(trim('as s')),length(trim(' s s '));
+----------------------+----------------------+----------------------+-----------------------+
| length(trim(' abc')) | length(trim('sds ')) | length(trim('as s')) | length(trim(' s s ')) |
+----------------------+----------------------+----------------------+-----------------------+
|                    3 |                    3 |                    4 |                     3 |
+----------------------+----------------------+----------------------+-----------------------+
1 row in set (0.05 sec)


mysql> select length(concat('abc','def'));       ##合并输出字符数
+-----------------------------+
| length(concat('abc','def')) |
+-----------------------------+
|                           6 |
+-----------------------------+
1 row in set (0.00 sec)
mysql> select upper('acs'),lower('ABC');      ##字母大小写转换
+--------------+--------------+
| upper('acs') | lower('ABC') |
+--------------+--------------+
| ACS          | abc          |
+--------------+--------------+
1 row in set (0.00 sec)
mysql> select left('asaidu',3),right('sasdbyw',3);    ##取固定前面后面几个
+------------------+--------------------+
| left('asaidu',3) | right('sasdbyw',3) |
+------------------+--------------------+
| asa              | byw                |
+------------------+--------------------+
1 row in set (0.00 sec)
mysql> select repeat('asd',3);         ##重复字符3次
+-----------------+
| repeat('asd',3) |
+-----------------+
| asdasdasd       |
+-----------------+
1 row in set (0.00 sec)
mysql> select length(concat('asd',space(3),'xyz'));    ##space(3)代表的是三个空格
+--------------------------------------+
| length(concat('asd',space(3),'xyz')) |
+--------------------------------------+
|                                    9 |
+--------------------------------------+
1 row in set (0.00 sec)
mysql> select replace('asddef','se','25');
+-----------------------------+
| replace('asddef','se','25') |
+-----------------------------+
| asddef                      |
+-----------------------------+
1 row in set (0.00 sec)
mysql> select replace('asddef','de','25');              ##将前面的字符串相应 的字符替换成后面字符
+-----------------------------+
| replace('asddef','de','25') |
+-----------------------------+
| asd25f                      |
+-----------------------------+
1 row in set (0.00 sec)
mysql> select strcmp(5,5)                ##比较大小
    -> ;
+-------------+
| strcmp(5,5) |
+-------------+
|           0 |
+-------------+
1 row in set (0.00 sec)
mysql> select strcmp(6,5);
+-------------+
| strcmp(6,5) |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)
mysql> select strcmp(4,5);
+-------------+
| strcmp(4,5) |
+-------------+
|          -1 |
+-------------+
1 row in set (0.00 sec)
mysql> select substring('sadecsas',3,3);          #从第三个起显示三个字符
+---------------------------+
| substring('sadecsas',3,3) |
+---------------------------+
| dec                       |
+---------------------------+
1 row in set (0.00 sec)
mysql> select reverse('asd');                         ##倒换字符
+----------------+
| reverse('asd') |
+----------------+
| dsa            |
+----------------+
1 row in set (0.00 sec)

日期时间函数

MySQL 也支持日期时间处理,提供了很多处理日期和时间的函数。一些常用的日期时间函数
字符串函数 描述
curdate() ---------------- 返回当前时间的年月日
curtime() ------------- --返回当前时间的时分秒
now() ------------------- -返回当前时间的日期和时间
month(x) ----------------返回日期 x 中的月份值
week(x) -----------------返回日期 x 是年度第几个星期
hour(x) ------------------返回 x 中的小时值
minute(x) ----------------返回 x 中的分钟值
second(x) --------------- 返回 x 中的秒钟值
dayofweek(x) ------------返回 x 是星期几,1 星期日,2 星期一
dayofmonth(x) ----------计算日期 x 是本月的第几天
dayofyear(x) -------------计算日期 x 是本年的第几天

mysql> select curdate(),curdate(),now();      //查询当前的时间年月日  查询当前的时间时分秒
+------------+------------+---------------------+
| curdate()  | curdate()  | now()               |
+------------+------------+---------------------+
| 2020-10-16 | 2020-10-16 | 2020-10-16 10:32:25 |
+------------+------------+---------------------+
1 row in set (0.00 sec)
mysql> select month('202-10-16'),week('2020-10-16'),hour('10:35');    //查询月份 查询是一年的第几周 查询()最中的小时值
+--------------------+--------------------+---------------+
| month('202-10-16') | week('2020-10-16') | hour('10:35') |
+--------------------+--------------------+---------------+
|                 10 |                 41 |            10 |
+--------------------+--------------------+---------------+
1 row in set (0.00 sec)
mysql> select week(curdate());      //查询当前的时刻是一年中的第几周
+-----------------+
| week(curdate()) |
+-----------------+
|              41 |
+-----------------+
1 row in set (0.00 sec)
mysql> select week(now()),momth(now()),hour(now()),minute(now()),second(now()),dayofweek(now());
ERROR 1305 (42000): FUNCTION school.momth does not exist        //这个报错是因为打错了month
mysql> select week(now()),month(now()),hour(now()),minute(now()),second(now()),dayofweek(now());
//查询当前的周 月 时  分钟   秒数   返回事星期几1代表星期天  2代表周一
+-------------+--------------+-------------+---------------+---------------+------------------+
| week(now()) | month(now()) | hour(now()) | minute(now()) | second(now()) | dayofweek(now()) |
+-------------+--------------+-------------+---------------+---------------+------------------+
|          41 |           10 |          10 |            39 |            17 |                6 |
+-------------+--------------+-------------+---------------+---------------+------------------+
1 row in set (0.00 sec)
mysql> select dayofmonth(now()),dayofyear(now());     //查询当前的时间是本月的第几天和本年的第几天
+-------------------+------------------+
| dayofmonth(now()) | dayofyear(now()) |
+-------------------+------------------+
|                16 |              290 |
+-------------------+------------------+
1 row in set (0.00 sec)

存储过程

前面学习的 MySQL 相关知识都是针对一个表或几个表的单条 SQL 语句,使用这样的SQL 语句虽然可以完成用户的需求,但在实际的数据库应用中,有些数据库操作可能会非常复杂,可能会需要多条 SQL 语句一起去处理才能够完成,这时候就可以使用存储过程, 轻松而高效的去完成这个需求。

存储过程简介

MySQL 数据库存储过程是一组为了完成特定功能的 SQL 语句的集合。存储过程这个功能是从 5.0 版本才开始支持的,它可以加快数据库的处理速度,增强数据库在实际应用中的灵活性。存储过程在使用过程中是将常用或者复杂的工作预先使用 SQL 语句写好并用一个指定的名称存储起来,这个过程经编译和优化后存储在数据库服务器中。当需要使用该存储过程时,只需要调用它即可。操作数据库的传统 SQL 语句在执行时需要先编译,然后再去执行,跟存储过程一对比,明显存储过程在执行上速度更快,效率更高。
存储过程在数据库中创建并保存,它不仅仅是 SQL 语句的集合,还可以加入一些特殊的控制结构,也可以控制数据的访问方式。存储过程的应用范围很广,例如封装特定的功能、 在不同的应用程序或平台上执行相同的函数等等。如果了解一些编程语言,可能会发现存储过程更像是面向对象方法的模拟。

存储过程的优点:

存储过程执行一次后,生成的二进制代码就驻留在缓冲区,之后如果再次调用的话,将 直接调用二进制代码,使得存储过程的执行效率和性能得到大幅提升。
存储过程是 SQL 语句加上控制语句的集合,有很强的灵活性,可以完成复杂的运算。
存储过程存储在服务器端,客户端调用时,直接在服务器端执行,客户端只是传输的调 用语句,从而可以降低网络负载。
存储过程被创建后,可以多次重复调用,它将多条 SQL 封装到了一起,可随时针对 SQL
语句进行修改,不影响调用它的客户端。
存储过程可以完成所有的数据库操作,也可以通过编程的方式控制数据库的信息访问权 限。

存储过程原理图解

在这里插入图片描述

创建存储过程

使用 CREATE PROCEDURE 语句创建存储过程,其语法格式如下所示。
CREATE PROCEDURE <过程名> ( [过程参数[,…] ] ) <过程体>
[过程参数[,…] ] 格式
[ IN | OUT | INOUT ] <参数名><类型>

存储过程的名称应该尽量避免选取与 MySQL 内置的函数或者字段相同的名称,否则会发生错误。存储过程可以添加参数,具有自己的参数列表。参数包括参数名和其对应的类型。 存在多个参数时,参数列表之间用逗号进行分隔。创建存储过程的时候可以不使用参数,但是括号要存在,也可以有一个或多个参数。
MySQL 的参数分为:输入参数、输出参数和输入/输出参数,分别用 IN、OUT 和 INOUT 三个关键字表示。其中,输入参数可以传递给一个存储过程;输出参数用于存储过程需要返回一个操作结果的情形,而输入/输出参数既可以充当输入参数也可以充当输出参数。
此外,存储过程的主体部分,被称为过程体,包含了在调用时必须执行的 SQL 语句。这个部分以关键字 BEGIN 开始,以关键字 END 结束。若过程体中只有一条 SQL 语句,则可以省略 BEGIN-END 标志。
在存储过程的创建过程中,会用到 DELIMITER 命令。因为在 MySQL 中,服务器处理SQL 语句默认是以分号作为语句结束标志的,过程体中由多条 SQL 语句构成,每条 SQL 后面都是分号结尾,那么 MySQL 服务器在处理时遇到第一条 SQL 语句就会结束整个过程, 不再去处理后面的 SQL 语句。为了解决这个问题,在创建存储过程时,使用 DELIMITER 命令,如下所示。

存储过程基本语法

mysql> DELIMITER $$
//省略存储过程其他步骤
mysql> DELIMITER ; //分号前有空格

要创建存储过程,必须要具有 CREATE ROUTINE 权限。
使用 SHOW PROCEDURE STATUS 命令查看数据库中存在哪些存储过程。如果要查看某个存储过程的具体信息,则可以使用SHOW CREATE PROCEDURE <存储过程名称>。 (这个不用看基本上看不懂)

mysql> delimiter $$
mysql> create procedure out_paras(out p int)
    -> begin
    -> select p;
    -> set p=2;
    -> select p;
    -> end
    -> $$
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;

删除存储过程

存储过程创建之时是存储到 MySQL 数据库中的,当程序不在调用这个存储过程时,也就意味这个存储过程被废弃了,废弃的存储过程需要从数据库中将其删除。使用 DROP PROCEDURE 语句即可删除存储过程,其语法格式具体如下。

DROP { PROCEDURE | FUNCTION } [ IF EXISTS ] <过程名>

从以上语法结构可以看出,在删除时存储过程的名字是放到最后的,前面可以添加 IF EXISTS 这个关键字,其主要作用是防止因删除不存在的存储过程而引发的错误。删除存储过程的具体操作如下所示。
下面是先创建在删除

mysql> delimiter $$
mysql> create procedure peng()
    -> begin
    -> select * from info limit 3;
    -> end $$
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql> call peng;
+----+----------+-------+-------+------+
| id | name     | score | hoddy | addr |
+----+----------+-------+-------+------+
|  1 | zhangsan | 81.00 |     3 | NULL |
|  2 | lisi     | 90.00 |     1 |      |
|  3 | wangwu   | 95.00 |     2 | nj   |
+----+----------+-------+-------+------+
3 rows in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> drop procedure peng;
Query OK, 0 rows affected (0.00 sec)
mysql> call peng;
ERROR 1305 (42000): PROCEDURE school.peng does not exist

需要注意的是:存储过程名称后面没有参数列表,也没有括号。在删除之前,必须确认 该存储过程没有任何依赖关系,否则会导致与之关联的存储过程无法运行。

存储过程之in的实验

mysql> delimiter $$          //创建存储过程开始
mysql> create procedure lap(in a int)           //存储过程创建的固定用法 存储过程名为lap 其中in是输入a其中int是类型
    -> begin                             	//开始
    -> declare b int;				//声明一个变量b 类型为int类型
    -> set b=0;					//输入b 的初始值为0
    -> create table t (int_a int(4),int_b int(4));	//创建表t中有两个字段
    -> while a<10 do				//执行while循环 条件是a<10的时候
    -> insert into t values (a,b);		//往t表中插入数值a和b
    -> set a=a+1;				//每次循环的时候输入a比上一次多1
    -> set b=b+3;				//每次循环的时候输入b比上一次多3
    -> end while;				//结束循环
    -> end $$					//结束存储过程
    
Query OK, 0 rows affected (0.06 sec)
mysql> delimiter ;        			//存储过程结束
mysql> set @a=1;				//输入一个值让a=1
Query OK, 0 rows affected (0.00 sec)

mysql> call lap(@a);				//用call命令来调用存储过程 这个必须要有 不然你看不到t表
Query OK, 1 row affected (0.10 sec)

mysql> show tables;				//查看数据库中的表
+------------------+
| Tables_in_school |
+------------------+
| info             |
| t                |
+------------------+
2 rows in set (0.00 sec)

mysql> select * from t;				//查看刚才的存储过程表的信息
+-------+-------+
| int_a | int_b |
+-------+-------+
|     1 |     0 |
|     2 |     3 |
|     3 |     6 |
|     4 |     9 |
|     5 |    12 |
|     6 |    15 |
|     7 |    18 |
|     8 |    21 |
|     9 |    24 |
+-------+-------+
9 rows in set (0.00 sec)

下面实验是要求建一个表格 然后插入学生名字和成绩后能自动评估学生成绩等级

mysql> DELIMITER $$
mysql> create procedure tt(in n varchar(10),in s int (4))
    -> begin
    -> declare h varchar(10);
    -> if s<60 then
    -> set h='不合格';
    -> elseif s between 60 and 75 then
    -> set h='合格';
    -> elseif s between 75 and 90 then
    -> set h='良好';
    -> else
    -> set h='优秀';
    -> end if;
    -> insert into info (name,score,hobby) values (n,s,h);
    -> end $$
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;
mysql> create table info(id int(4) not null auto_increment,name varchar(10) not null,score int(4) not null,hobby varchar(10) not null,primary key (id));       //先创建一个表对应的表名与储存过程写的一样
Query OK, 0 rows affected (0.01 sec)

mysql> call tt('yanha',100);               		//输入学生的名字和成绩
Query OK, 1 row affected (0.01 sec)

mysql> select * from info;				//查看结果
+----+------------+-------+--------+
| id | name       | score | hobby  |
+----+------------+-------+--------+
|  1 | zhangsan   |    98 | 优秀   |
|  2 | yanha |   100 | 优秀   |
+----+------------+-------+--------+
2 rows in set (0.00 sec)
mysql> call tt('zhubajie',80);
Query OK, 1 row affected (0.00 sec)

mysql> select * from info;
+----+------------+-------+--------+
| id | name       | score | hobby  |
+----+------------+-------+--------+
|  1 | zhangsan   |    98 | 优秀   |
|  2 | yanha |   100 | 优秀   |
|  3 | zhubajie   |    80 | 良好   |
+----+------------+-------+--------+
mysql> call tt('刘四',80);
Query OK, 1 row affected (0.00 sec)

mysql> select * from info;
+----+------------+-------+--------+
| id | name       | score | hobby  |
+----+------------+-------+--------+
|  1 | zhangsan   |    98 | 优秀   |
|  2 | yanha        |   100 | 优秀   |
|  3 | zhubajie   |    80 | 良好   |
|  4 | 刘四           |    80 | 良好   |
+----+------------+-------+--------+
4 rows in set (0.00 sec)

上面的实验常遇到的报错

mysql> call tt(@n,@s);
ERROR 1054 (42S22): Unknown column 'hobby' in 'field list'       //说hobby没有在表中 原因我将hobby写成了hoddy
mysql> alter table info change hoddy hobby int(11);		//将hoddy 改成hobby
Query OK, 0 rows affected (0.00 sec)
##问题二
mysql> create table info (id int(10) not null auto_increment,name varchar(10) not null,score int(4) not null,hobby int(10) not null);
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key								//创建表的时候它说自增类型的必须要设置成主键

mysql> create table info (id int(10) not null auto_increment,name varchar(10) not null,score int(4) not null,hobby int(10) not null,primary key (id));			//添加主键字段后成了
Query OK, 0 rows affected (0.01 sec)

##问题三
mysql> call tt('zhoutao',50);
ERROR 1366 (HY000): Incorrect integer value: '不合格' for column 'hobby' at row 1		//意思就是类型不对

mysql> alter table info change hobby hobby varchar(10);		//改变hobby的类型为varchar
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc info;						//查看表结构
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(10)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(10) | NO   |     | NULL    |                |
| score | int(4)      | NO   |     | NULL    |                |
| hobby | varchar(10) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> call tt('zhoutao',50);					//在输入名字和成绩 成功
Query OK, 1 row affected (0.00 sec)

mysql> select * from info;					//看有没有输进去
+----+---------+-------+-----------+
| id | name    | score | hobby     |
+----+---------+-------+-----------+
|  1 | zhoutao |    50 | 不合格    |
+----+---------+-------+-----------+
1 row in set (0.00 sec)

还有一个有趣的可以实现 改相同评估的成绩的 容易理解不在解释

mysql> select * from info;
+----+---------+-------+-----------+
| id | name    | score | hobby     |
+----+---------+-------+-----------+
|  1 | zhoutao |    50 | 不合格    |
|  2 | zhoutao |    90 | 良好      |
+----+---------+-------+-----------+
2 rows in set (0.00 sec)
mysql> update info set score=80 where name='zhoutao';
Query OK, 2 rows affected (0.06 sec)

Rows matched: 2  Changed: 2  Warnings: 0
mysql> select * from info;
+----+---------+-------+-----------+
| id | name    | score | hobby     |
+----+---------+-------+-----------+
|  1 | zhoutao |    80 | 不合格    |
|  2 | zhoutao |    80 | 良好      |
+----+---------+-------+-----------+
2 rows in set (0.00 sec)

猜你喜欢

转载自blog.csdn.net/Laiyunpeng666/article/details/109096897