MariaDBMySQL存储过程、游标基础应用举例说明

by:授客 QQ1033553122

测试环境:

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存储过程、游标基础应用举例说明的更多相关文章

  1. MySQL存储过程 游标

    MySQL存储过程  游标 如何在存储过程中使用MySQL游标来遍历SELECT语句返回的结果集 MySQL游标简介 要处理存储过程中的结果集,请使用游标.游标允许您迭代查询返回的一组行,并相应地处理 ...

  2. mysql存储过程游标嵌套循环

    自己写的一个mysql存储过程如下: BEGIN DECLARE _did bigint(20);DECLARE _count int;DECLARE s1 int;DECLARE cur_1 CUR ...

  3. ava基础MySQL存储过程 Java基础 JDBC连接MySQL数据库

    1.MySQL存储过程   1.1.什么是存储过程 带有逻辑的sql语句:带有流程控制语句(if  while)等等 的sql语句   1.2.存储过程的特点 1)执行效率非常快,存储过程是数据库的服 ...

  4. MySQL 存储过程/游标/事务

    将会用到的几个表 mysql> DESC products; +------------+--------------+------+-----+---------+-------------- ...

  5. php调用mysql存储过程游标

    <?php $dbtype = 'mysql'; $host = 'localhost'; $dbname = 'test'; $dsn = "$dbtype:host=$host;d ...

  6. mysql存储过程游标加计划任务事件调度器

    存储过程加事件调度器 -- 存储过程 (多个)游标的使用 临时表的使用(让执行时间从一个小时降低到5分钟)DELIMITER $$ DROP PROCEDURE IF EXISTS `eval_cal ...

  7. MySQL存储过程入门基础

    创建存储过程无参语法: delimiter // create procedure 函数名() begin 业务逻辑 end // call 函数名() 通过函数名调用存储过程 创建存储过程有参与法: ...

  8. mysql 存储过程 游标嵌套

    基本表temp 包括 name, type, sendCity, getCity 分别对应物流送货司机名, 倒车的第几段, 发货城市, 收货城市 表结构 -- -------------------- ...

  9. MySQL 存储过程游标

    一.创建游标 游标用declare语句创建.如下面的例子所示: create procedure test2() begin declare cursorTest cursor for select ...

随机推荐

  1. 06-03 Java 面向对象思想概述、开发设计特征,类和对象的定义使用,对象内存图

    面向对象思想概述.开发设计特征 1:面向对象思想 面向对象是基于面向过程的编程思想. 面向过程:强调的是每一个功能的步骤 面向对象:强调的是对象,然后由对象去调用功能 2:面向对象的思想特点 A:是一 ...

  2. 推荐几个 WebSocket 服务端实现

    http://netty.io/http://socket.io/https://github.com/StackExchange/NetGainhttps://github.com/SignalR/ ...

  3. Window服务与Quartz.NET

    Quartz.NET: http://quartznet.sourceforge.net/ (现为2.2版本) Sourceforge:http://sourceforge.net/projects/ ...

  4. JSPatch动态更新APP

    JSPatch,只需在项目中引入极小的引擎,就可以使用JavaScript调用任何Objective-C的原生接口,获得脚本语言的能力:动态更新APP,替换项目原生代码修复bug. 用途 是否有过这样 ...

  5. 记住,永远不要在MySQL中使用“utf8”编码[转载]

    记住,永远不要在MySQL中使用“utf8”编码 原创: 无明.Adam 聊聊架构 6月15日 最近工作中我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一 ...

  6. [Java初探实例篇02]__流程控制语句知识相关的实例练习

    本例就流程控制语句的应用方面,通过三个练习题来深入学习和巩固下学习的流程控制语句方面的知识,设计到,if条件判断语句,switch多分支语句,for循环语句及其嵌套多层使用,while循环语句. 练习 ...

  7. Chrome 开发工具之Timeline/Performance

    之前有说到Element,Console,Sources大多运用于debug,Network可用于debug和查看性能,今天的主角Timeline(现已更名Performance)更多的是用在性能优化 ...

  8. 19-hadoop-fof好友推荐

    好友推荐的案例, 需要两个job, 第一个进行好友关系度计算, 第二个job将计算的关系进行推荐 1, fof关系类 package com.wenbronk.friend; import org.a ...

  9. C# DateTime 转 JavaScript Date

    @{ var minTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; var nowTicks = DateTime ...

  10. ASP.NET MVC5+EF6+LayUI实战教程,通用后台管理系统框架(1)

    文章转自:http://www.xuboyi.com/298.html 前言 网站运营有一段时间了,记录的内容都是杂七杂八的,思前想后,决定给大家分享一套ASP.Net的系列教程.手把手的做一套通用后 ...