MySQL新学知识(二)MySQL存储过程

MySQL新学知识(二)


前言

👨‍💻👨‍🌾📝记录学习成果,以便温故而知新

本专题把一阶段学到知识MySQL做一个总结


一、mysql客户端建立存储过程

MySQL文档https://dev.mysql.com/doc/refman/8.0/en/stored-programs-defining.html中一个例子虽然简单,但是很有代表性。

例子如下:

mysql> delimiter //

mysql> CREATE PROCEDURE dorepeat(p1 INT)

-> BEGIN

-> SET @x = 0;

-> REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;

-> END

-> //

Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

mysql> CALL dorepeat(1000);

Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @x;

±-----+

| @x |

±-----+

| 1001 |

±-----+

1 row in set (0.00 sec)

客户端效果截图如下:

其中delimiter //是重新定义分隔符,默认分隔符是";"。因为存储过程体里语句的分隔符是";",而存储过程体的分隔符也是";",这样会有冲突,所以需要重新定义,这样存储过程体里语句使用";"作为分隔符就不会与存储过程体的分隔符"//"冲突了。

这个例子还演示了REPEAT循环与存储过程调用。

二、工具中建立存储过程

编辑已经建立的存储过程,与客户端的区别就是不要重新定义分隔符,省去了麻烦,如下图:

三、几个常用存储过程的例子

刚开始学Java的时候有种思路是所有的数据库操作都是用代码来实现以保证程序逻辑的可移植,防止换数据库还需要修改存储过程,所以对于存储过程的学习是浅尝辄止。后来发现有时存储过程还是很管用的,记录如下:

1.执行单语句

下面以新增用户权限为例

sql 复制代码
CREATE DEFINER=`root`@`%` PROCEDURE `SP_ADD_PRIVILEGES`(IN `moduleName` varchar(100))
BEGIN
    -- 模块名称
    -- 如call SP_ADD_PRIVILEGES('模块名称');
    SET @grant_privileges = CONCAT('INSERT INTO t_privileges(user_id, module_name)
    SELECT user_id, \'', moduleName, '\' 
    FROM t_user
    WHERE role_name != \'Admin\' AND user_id NOT IN (SELECT user_id FROM t_privileges WHERE module_name = \'', moduleName, '\')');
    
    PREPARE stmt FROM @grant_privileges;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END

用户表内容如图:

调用存储过程如下:

sql 复制代码
CALL SP_ADD_PRIVILEGES('新增用户');

调用结果:

调用后t_privileges表内容:

这个存储过程的要点在于拼接语句。

2.循环执行语句

下面以给T开头的用户赋单表权限为例

sql 复制代码
CREATE DEFINER=`root`@`%` PROCEDURE `SP_GRANTTABLE`(IN `tableName` varchar(100))
BEGIN
    -- 根据表名设置权限
    -- 如call SP_GRANTTABLE('test.t_privileges');
    DECLARE has_next boolean DEFAULT TRUE;
    DECLARE num int DEFAULT 0;
    DECLARE sqlStmt varchar(5000);
    DECLARE sqlResult CURSOR FOR SELECT CONCAT('GRANT Select ON TABLE ', tableName, ' TO `', User, '`@`%`;') FROM mysql.user WHERE User LIKE 'T%';
    DECLARE CONTINUE HANDLER FOR not found SET has_next = FALSE;
    
    OPEN sqlResult;
    EXIT_LOOP: LOOP
        FETCH sqlResult INTO sqlStmt;
        IF !has_next THEN
            LEAVE EXIT_LOOP;
        END IF;
        
        SET @grant_privileges = sqlStmt;
        PREPARE stmt FROM @grant_privileges;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET num = num + 1;
    END LOOP;
    CLOSE sqlResult;
    
    SELECT CONCAT('共授权', num, '位用户') AS '返回信息';
END

如下图红框新建两个用户:

调用存储过程如下:

sql 复制代码
CALL SP_GRANTTABLE('test.t_privileges');

调用结果如下:

这个存储过程要点:

  1. 定义游标CURSOR;
  2. 为"not found"定义"CONTINUE HANDLER",作用是推出异常;
  3. 最后一个查询语句用户调用结果返回

2个列子介绍一些有用知识点,以后要是学到新的再逐步补充到这篇。

相关推荐
鸽芷咕11 分钟前
KingbaseES 调参先看执行计划,参数是答案不是起点
数据库
这个DBA有点耶34 分钟前
MySQL 8.0直方图:统计信息升级了,执行计划为什么还是选错?
数据库·mysql·代码规范
老纪的技术唠嗑局3 小时前
把 seekdb 塞进 iOS App:让混合检索嵌入手机
数据库
ClouGence3 小时前
开源数据库管理工具 CloudDM 新版本发布,支持 OpenSearch、IoTDB 数据源
数据库·开源
徐小黑ACG4 小时前
Redis-基础
数据库·redis·缓存
火山引擎开发者社区4 小时前
案例实践 | 让 Agent 读懂业务口径:ContextSearch 在广告数据查询中的实践
数据库
10年前端老司机5 小时前
Milvus 8种检索能力实践
数据库·python·agent
aiks_yuan5 小时前
MySQL 深分页 LIMIT 越翻越慢怎么办:300 万行实测 OFFSET、延迟关联和 keyset 的耗时差距(MySQL 8.2)
mysql
Decay__6 小时前
14_MySQL 高可用与容灾架构 —— MGR / InnoDB Cluster / Keepalived+VIP / 双主 / 读写分离 / 两地三中心
运维·数据库·sql·mysql·架构
freejackman6 小时前
【实战三】撕开脱敏盲区:深度解析 CASE WHEN 与窗口函数血缘
大数据·数据库·sql