MariaDB MariaDB、MySQL存储过程、游标基础应用举例说明
MariaDB、MySQL存储过程、游标基础应用举例说明
by:授客 QQ:1033553122
测试环境:
MariaDB-10.0.19-centos7-x86_64
实践操作:
# 创建测试数据库
DROP DATABASE IF EXISTS testdb1;
CREATE DATABASE testdb1;
# 创建测试表-余额表
DROP TABLE IF EXISTS account;
CREATE TABLE IF NOT EXISTS account
(user_id BIGINT PRIMARY KEY, # 用户id
account BIGINT # 账户余额
);
# 创建测试表-创建利润分成表
CREATE TABLE IF NOT EXISTS profit_sharing
(order_id BIGINT PRIMARY KEY, # 订单ID
user_id BIGINT, # 用户ID
total_price DECIMAL(9,4), # 交易价格
share_price DECIMAL(9,4), # 消费返利
FOREIGN KEY(user_id) REFERENCES account(user_id)
);
# 插入测试数据
INSERT INTO account VALUES(1001, 10000);
INSERT INTO account VALUES(1002, 9000);
INSERT INTO profit_sharing VALUES(100001, 1001, 99, 10);
INSERT INTO profit_sharing VALUES(100002, 1002, 90, 5);
# 场景1:存储过程中的每个查询语句都只返回一条记录
# 创建存储过程
DROP PROCEDURE IF EXISTS proc_varify_profit_sharing; # 如果存在proc_varify_profit_sharing则先删除
DELIMITER // # 使用DELIMITER命令来把语句定界符从 ; 变为 // # 注意,定界符可以是其它符号,比如 $ ,但是不能为 \ ,因为它是转义字符
#说明,通常情况下,mysql遇到分号 ; 则判断语句结束,并执行该语句,这里DELIMITER // 告诉mysql,遇到 // 则表示语句结束,执行语句
CREATE PROCEDURE proc_varify_profit_sharing(
user_id BIGINT,
account_init BIGINT,
order_id BIGINT
)
BEGIN
# 声明局部变量
DECLARE account_final BIGINT; # 用于存储最终余额
DECLARE total_price DECIMAL(9, 4); # 用于存储交易总金额
DECLARE share_price DECIMAL(9, 4) DEFAULT 0.00; # 用于存储消费返利金额
# 说明:BEGIN END;之间定义的变量为局部变量,基础形式:DECLARE 变量名 数据类型 默认值
# 定义游标
DECLARE cur_get_account_final CURSOR FOR SELECT t1.account FROM account t1 WHERE t1.user_id=user_id;
DECLARE cur_varify_account CURSOR FOR SELECT t2.share_price, t2.total_price FROM profit_sharing t2
WHERE t2.user_id=user_id AND t2.order_id = order_id;
# 基础语法说明:DECLARE cursor_name CURSOR FOR select_statement;
# 打开游标
OPEN cur_get_account_final;
OPEN cur_varify_account;
#基础语法说明:OPEN cursor_name;
# 获取数据
FETCH cur_get_account_final INTO account_final;
FETCH cur_varify_account INTO share_price, total_price;
#基础语法说明:FETCH cursor_name INTO variable1[, variable2,...]; #读取一行记录(如果有的话),
#并将记录中各项的值赋值给变量variable1,variable2,...
#注意,变量个数要和游标指定查询生成记录的记录项的数目要相同,通俗的说,查询生成记录,包含多少列,就指定多少个变量,一一对应
# 验证金额增减的准确性
SET @tmp = account_final + total_price - share_price; #使用用户变量@tmp,存放中间计算结果
SELECT IF(@tmp=account_init, 'right', 'wrong') AS 'result';
#说明:用户变量(用户变量也归属局部变量)的定义:@变量名,,
#注意:
#1.mysql中用户变量可不用事前声明,在用的时候直接用“@变量名”使用就可以了,
#2.用户变量跟mysql客户端是绑定的,设置的变量,只对当前用户使用的客户端生效
#说明:用SET给变量赋值: SET 变量=value; 或者 SET 变量:=value; 如上语句所示
小知识:可以用SELECT给变量赋值,类似的有,SELECT 变量:=value; 或 SELECT 变量:=colunm_name FROM table_name WHERE …;
注意:使用SELECT时必须用 :=
# 关闭游标
CLOSE cur_get_account_final;
CLOSE cur_varify_account;
#基础语法说明:CLOSE cursor_name;
END;
//
DELIMITER ; # 还原定界符为 ;
# 调用存储过程
CALL proc_varify_profit_sharing(1001, 10089, 100001);
#调用形式说明:CALL procedure_name()(无参数的话)、CALL procedure_name(arg1[, arg2, ...])(带参数)
# "场景1"不用游标的等价实现
# 创建存储过程
DROP PROCEDURE IF EXISTS proc_varify_profit_sharing;
DELIMITER //
CREATE PROCEDURE proc_varify_profit_sharing(
userID BIGINT, # 注意,当存储过程参数如果用于存储过程中,表查询语句的WHERE子句,作为筛选条件值时,如果未指定要查询表的表别名,则不能和表的列名相同,参见如下
account_init BIGINT,
orderID BIGINT
)
BEGIN
# 定义局部变量
DECLARE account_final BIGINT; # 用于存储最终余额
DECLARE total_price1 DECIMAL(9, 4); # 用于存储交易总金额
DECLARE share_price1 DECIMAL(9, 4); # 用于存储消费返利金额
#获取数据
SELECT account INTO account_final FROM account WHERE user_id = userID LIMIT 0,1; # LIMIT 0, 1 确保只返回一条记录
# 把share_price, total_price分别的查询结果分别赋值给局部变量share_price, total_price
SELECT share_price, total_price INTO share_price1, total_price1 FROM profit_sharing
WHERE user_id=userID AND order_id = orderID LIMIT 0,1;
#注意:
#1、未使用游标的情况下,查询语句使用表别名需要添加 AS,如 SELECT t1.account INTO account_final FROM account t1; 报错,提示t1为 Undeclared variable ,SELECT t1.account INTO account_final FROM account AS t1则不会报错
#2、SELECT column1, ... INTO variable1, ...; 如果column1和variable1名称不可以相同,否则取不到值,variable1最终的值为NULL(MariaDB下测试
# 验证金额增减的准确性
SET @tmp = account_final + total_price1 - share_price1; # 注意:NULL + value1 + ... = NULL
SELECT IF(@tmp=account_init, 'right', 'wrong') AS 'result';
END;
//
DELIMITER ;
CALL proc_varify_profit_sharing(1001, 10089, 100001);
# 场景2:返回一个结果集,多条记录(循环读取
# 创建存储过程
DROP PROCEDURE IF EXISTS proc_test;
DELIMITER //
CREATE PROCEDURE proc_test()
BEGIN
# 声明局部变量
DECLARE order_id BIGINT; # 用于存储订单号
DECLARE total_price DECIMAL(9, 4); # 用于存储交易总金额
DECLARE share_price DECIMAL(9, 4) DEFAULT 0.00; # 用于存储消费返利金额
#DECLARE no_more_record INT DEFAULT 0; # 是否还有记录标识
DECLARE no_more_record INT; # 是否还有记录标识
# 定义游标
DECLARE cur_get_order_info CURSOR FOR SELECT share_price, total_price FROM profit_sharing;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_record = 1; #当游标或者SQL选择语句没有返回值时,设置 no_more_record=1后继续执行
# 打开游标
OPEN cur_get_order_info;
# 读取数据 ======行1
FETCH cur_get_order_info INTO total_price, share_price;
SET no_more_record = 0;
WHILE no_more_record <> 1 DO #
如果存在下一跳记录,则继续读取
FETCH cur_get_order_info INTO total_price, share_price;
END WHILE;
# ===============行2
#注意:如果把行1到行2之间的语句改成如下
#WHILE no_more_record <> 1 DO #
如果存在下一跳记录,则继续读取
#
FETCH cur_get_order_info INTO total_price, share_price;
#END WHILE;
#那么,整个while循环体将执行3次(但是表里仅2条记录,为何这样呢?个人想法是这样的:
#第一次循环,no_more_record=0,执行FETCH语句,且游标指针停留在一条记录
#第二次循环,no_more_record=0,执行FETCH语句,且游标指针停留在二条记录
#第三次循环,no_more_record=0,执行FETCH语句,且游标指针移动到下一条,结果无记录,no_more_record=1,结束下次循环
#所以,while循环之前要先执行一次
#
关闭游标
CLOSE cur_get_order_info;
END;
//
DELIMITER ;
CALL proc_test();
MariaDB MariaDB、MySQL存储过程、游标基础应用举例说明的更多相关文章
- MySQL存储过程 游标
MySQL存储过程 游标 如何在存储过程中使用MySQL游标来遍历SELECT语句返回的结果集 MySQL游标简介 要处理存储过程中的结果集,请使用游标.游标允许您迭代查询返回的一组行,并相应地处理 ...
- mysql存储过程游标嵌套循环
自己写的一个mysql存储过程如下: BEGIN DECLARE _did bigint(20);DECLARE _count int;DECLARE s1 int;DECLARE cur_1 CUR ...
- ava基础MySQL存储过程 Java基础 JDBC连接MySQL数据库
1.MySQL存储过程 1.1.什么是存储过程 带有逻辑的sql语句:带有流程控制语句(if while)等等 的sql语句 1.2.存储过程的特点 1)执行效率非常快,存储过程是数据库的服 ...
- MySQL 存储过程/游标/事务
将会用到的几个表 mysql> DESC products; +------------+--------------+------+-----+---------+-------------- ...
- php调用mysql存储过程游标
<?php $dbtype = 'mysql'; $host = 'localhost'; $dbname = 'test'; $dsn = "$dbtype:host=$host;d ...
- mysql存储过程游标加计划任务事件调度器
存储过程加事件调度器 -- 存储过程 (多个)游标的使用 临时表的使用(让执行时间从一个小时降低到5分钟)DELIMITER $$ DROP PROCEDURE IF EXISTS `eval_cal ...
- MySQL存储过程入门基础
创建存储过程无参语法: delimiter // create procedure 函数名() begin 业务逻辑 end // call 函数名() 通过函数名调用存储过程 创建存储过程有参与法: ...
- mysql 存储过程 游标嵌套
基本表temp 包括 name, type, sendCity, getCity 分别对应物流送货司机名, 倒车的第几段, 发货城市, 收货城市 表结构 -- -------------------- ...
- MySQL 存储过程游标
一.创建游标 游标用declare语句创建.如下面的例子所示: create procedure test2() begin declare cursorTest cursor for select ...
随机推荐
- 剑指offer三从头到尾打印链表
一.题目: 输入一个链表,从尾到头打印链表每个节点的值. 二.解题方法: 方法一:采用递归的方式实现 方法二:借助堆栈的“后进先出”实现 import java.util.ArrayList; imp ...
- Storm中的定时任务
1.全局定时器 import java.util.Map; import backtype.storm.Config; import backtype.storm.Constants; import ...
- Unity学习系列一简介
一.简介 Unity的目标是为了提升"依赖注入"的思想,去建立更加松耦合的系统.patterns & practices 小组在那个时候实现DI的方式和我们现在认为的DI有 ...
- logback打印mybatis sql日志
近期在项目中调试sql,发现现有的配置 使用logback 无法打印出sql语句,原配置如下(修改为debug也不好使): <!--jdbc --><logger name=&quo ...
- 从nsq中学习如何优雅的退出go 网络程序
退出运行中的程序,可以粗暴的kill -9 $PID,但这样会破坏业务的完整性,有可能一个正在在执行的逻辑半途而费,从而产生不正常的垃圾数据. 本文总结在go语言中,如何能优雅的退出网络应用,涉及的知 ...
- 了解MySQL联表查询中的驱动表,优化查询,以小表驱动大表
一.为什么要用小表驱动大表 1.驱动表的定义 当进行多表连接查询时, [驱动表] 的定义为: 1)指定了联接条件时,满足查询条件的记录行数少的表为[驱动表] 2)未指定联接条件时,行数少的表为[驱动表 ...
- layer插件学习——弹框(自定义页)
本文是自己整理的关于layer插件的弹框样式结果 介绍: 官方介绍:layer至今仍作为layui的代表作,受众广泛并非偶然,而是这五年多的坚持,不断完善和维护.不断建设和提升社区服务,使得猿们纷纷自 ...
- Linux下删除Tomcat缓存
step1:进入Tomcat的bin目录,停止Tomcat服务 ./shutdown.sh step2:进入Tomcat的work目录,删除work目录里面的全部文件 step3.启动Tomcat服务 ...
- JavaScript 总结(前端常用工具类的封装)
JavaScript (class是ES6的新东西,看着不爽可以变,但主要还是里面的方法) 1. type 类型判断 class TypeFn { isString (o) { //是否字符串 ret ...
- SQL语句大全从基础到熟练(不含数据库高端操作)日常用户 三、
前言 昨天晚上回家忘记带钥匙导致在楼下站街三小时,鬼天气热的不要不要的然后我就在车里坐了会之后就.....zzZZ,哈哈睡的挺香的毕竟累了一天了 上两篇文章都是介绍的语法语句,本篇文章介绍下函数的使用 ...