存储过程,从新的视角看待数据库应用程序开发(游标,变量,结果集)

存储过程实战指南:从设计到跨数据库部署的完整解决方案 存储过程是数据库编程的核心技术之一,它将复杂的业务逻辑封装在数据库端,通过预编译和缓存执行计划来提升性能。其核心原理在于减少网络交互、保证事务原子性,并提供统一的数据操作接口,这对于处理计算密集型任务和高并发场景具有重要技术价值。在电商、金融、在线教育等需要复杂数据统计和报表生成的业务场景中,存储过程的应用尤为广泛。本文聚焦于存储过程的实战开发,深入探讨了如何结合动态SQL、游标等高级特性,并解决在MySQL、SQL Server、Oracle及达梦等不同数据库环境下的兼容性问题,特别是针对达梦数据库的编译 阅读详情

存储过程,从新的视角看待数据库应用程序开发(游标,变量,结果集)

by ColdZoo 2015年03月26日

通常情况下,在操作数据库里数据的时候,我们会选择一种编程语言(Java,C++, et al.),然后利用它们实现我们的业务逻辑。这种方法非常繁琐,并且在表结构发生修改的时候需要重写整个数据库访问模块。
实际上,现代的数据库系统已经为我们准备了另一套更加优雅的解决方案,也就是本文要讲到的——“存储过程”。
关于存储过程的定义,这里有详细的介绍。我们就不再赘述。


本文主要介绍MySQL中存储过程的几个关键而基础的语法(Syntax),涉及游标,结果集,变量,查询语句,DML,DDL。由于水平有限,如有谬误敬请指正

与其他教程不同,笔者决定不从语法开始,而是在工程中碰到问题的时候才讲解语法。因此,如果你需要语法方面的信息,请随时参考[这里]。下面来看看在实际的工程中,如何使用存储过程。

需求

我们需要对如下数据表中的数据进行处理:

数据表说明

表名说明
d_annotation保存的是标注信息,主键是AnnotaId
c_anp保存的是ANP(Adj. Noun Pair)中Adj.和Noun的Id,主键Anpid
c_vnp保存的是VNP(Verb. Noun Pair)中Verb.和Noun的Id,主键Vnpid
b_verb保存的是Verb的Id和Keyword(英文)
b_adj保存的是Adj.的Id和Keyword
b_noun保存的是Noun的Id和Keyword

此外,为了便于处理,我们准备了如下视图:

视图名说明
useful_data经过预处理后的可用数据,内有两个字段,AnnotaId 和 FileName,分别代表数据文件名和相应的标注Id。

关键字段

表字段含义
d_annotationAnnotaId标注信息的Id,每个标注信息均不相同,每个文件Id对应唯一一个AnnotaId
d_annotationAnpId* (*为1…8)该标注中第*个Anp的Id

需求

我们的需求是
对视图useful_data中给定的每一行数据进行处理,将每个文件名对应的一个Annotation中的ANP,VNP信息改为Adj,Verb信息。

例如,图片0001.jpg原来的标注信息是:VNP1(Cover
Face)+VNP2(Smile Man)+ANP1(Green Grassland) 我们要把以上信息转化为:Verb1(Cover)+Verb2(Smile)+Adj1(Green)

技术分析

要实现以上需求,我们需要执行下列步骤

  1. 循环遍历视图useful_data取出AnnotaId
  2. 根据AnnotaId 查询表 d_annotation, 取出ANPID 和 VNPID (有多个)
  3. 对每一个取出的ID,查询表c_anp和表c_vnp,取出Adj.和Verb.的ID,然后在b_verb 和 b_adj中得到动词和形容词的英文形式。综合之后便可以得到每个文件名对应的动词和形容词了。

实现

具体实现如下:

声明变量

以上三步中各个步骤的中间结果均需要保存到变量里,SQL的存储过程中可以用如下语法声明变量。

declare variable_name type default default_value

其中type为数据类型,常用的有

| INT | VARCHAR | CHAR |….

我们声明了如下变量

DECLARE Done INT DEFAULT 0;
declare annoid int;
declare fn varchar(45);


declare anp1 int;
declare anp2 int;
declare anp3 int;
declare anp4 int;
declare anp5 int;
declare anp6 int;
declare anp7 int;
declare anp8 int;

declare vnp1 int;
declare vnp2 int;
declare vnp3 int;
declare vnp4 int;
declare vnp5 int;
declare vnp6 int;
declare vnp7 int;
declare vnp8 int;

declare adj1 varchar(45);
declare adj1id varchar(45);
declare adj2 varchar(45);
declare adj2id varchar(45);
declare adj3 varchar(45);
declare adj3id varchar(45);
declare adj4 varchar(45);
declare adj4id varchar(45);
declare adj5 varchar(45);
declare adj5id varchar(45);
declare adj6 varchar(45);
declare adj6id varchar(45);
declare adj7 varchar(45);
declare adj7id varchar(45);
declare adj8 varchar(45);
declare adj8id varchar(45);

declare verb1 varchar(45);
declare verb1id varchar(45);
declare verb2 varchar(45);
declare verb2id varchar(45);
declare verb3 varchar(45);
declare verb3id varchar(45);
declare verb4 varchar(45);
declare verb4id varchar(45);
declare verb5 varchar(45);
declare verb5id varchar(45);
declare verb6 varchar(45);
declare verb6id varchar(45);
declare verb7 varchar(45);
declare verb7id varchar(45);
declare verb8 varchar(45);
declare verb8id varchar(45);

利用游标循环遍历数据表

声明了以上变量之后我们可以开始进行第一步,之前接触过存储过程的朋友肯定知道,存储过程中可以使用循环语句,那么我们要用循环语句来遍历数据表么?答案是否定的。

我们使用游标来遍历数据表,游标的语法如下:

DECLARE rs CURSOR FOR SELECT AnnotaId,FileName from useful_data;

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET Done = 1;

第一句用于声明游标,rs为游标的名称,FOR 后面为我们游标作用的语句。
第二句用于设置Handler,其作用是在游标移动到表的末尾时,设置Done变量为1,也就是退出我们下面这个循环

repeat
    ......  
    -- some other code;
    ......
    fetch rs into annoid,fn;
until Done end repeat;

注意上面那句

fetch rs into annoid,fn
意思是将游标指向的数据赋值给指定变量。

嵌套查询

遍历之后,我们得到了AnnotaId,我们还需要进行第二步的查询,那么在循环体内又该如何查询新的表呢?

select AnpId1,AnpId2,AnpId3,AnpId4,VnpIdA,VnpIdB,VnpIdC,VnpIdD from d_annotation where AnnotaId=annoid into anp1,anp2,anp3,anp4,vnp1,vnp2,vnp3,vnp4;

使用的select … into …
到这里我们有了ANP/VNP 的ID

下面我们用相似的步骤得到剩下变量的值:

        select AdjId from c_anp where AnpId = anp1 into adj1id;
        select Keyword from b_adj where SynId=adj1id into adj1;
        select AdjId from c_anp where AnpId = anp2 into adj2id;
        select Keyword from b_adj where SynId=adj2id into adj2;
        select AdjId from c_anp where AnpId = anp3 into adj3id;
        select Keyword from b_adj where SynId=adj3id into adj3;
        select AdjId from c_anp where AnpId = anp4 into adj4id;
        select Keyword from b_adj where SynId=adj4id into adj4;

        select VerbId from c_vnp where VnpId=vnp1 into verb1id; 
        select Keyword from b_verb where SynId=verb1id into verb1;
        select VerbId from c_vnp where VnpId=vnp2 into verb2id; 
        select Keyword from b_verb where SynId=verb2id into verb2;
        select VerbId from c_vnp where VnpId=vnp3 into verb3id; 
        select Keyword from b_verb where SynId=verb3id into verb3;
        select VerbId from c_vnp where VnpId=vnp4 into verb4id;
        select Keyword from b_verb where SynId=verb4id into verb4;

在查询中使用DML和DDL

进行到这一步,我们已经得到了动词和名次,我们需要用DML(data manipulate language)语言,插入结果到新的表中

insert into t_word_from_anno(AnnotaId,verb1_id,verb1,verb2_id,verb2,verb3_id,verb3,verb4_id,verb4,adj1_id,adj1,adj2_id,adj2,adj3_id,adj3,adj4_id,adj4,FileName) values(annoid,verb1id,verb1,verb2id,verb2,verb3id,verb3,verb4id,verb4,adj1id,adj1,adj2id,adj2,adj3id,adj3,adj4id,adj4,fn);

结果展示

select * from t_word_from_anno

# id, AnnotaId, verb1_id, verb1, verb2_id, verb2, verb3_id, verb3, verb4_id, verb4, adj1_id, adj1, adj2_id, adj2, adj3_id, adj3, adj4_id, adj4, FileName

'16842', '45', 'SID-02148788-V', 'show', NULL, NULL, NULL, NULL, NULL, NULL, 'SID-01048406-A', 'happy', NULL, NULL, NULL, NULL, NULL, NULL, '1379559307320.gif'

大功告成。

常见错误

Syntax error: missing ‘end’

请检查声明语句和其他语句的顺序是否正确,在SQL的存储过程中,声明语句必须放在其他所有语句之前。

delete from t_word_from_anno where id >0;
delete from t_verbs where 1>0;
delete from t_adjs where 1>0;

DECLARE Done INT DEFAULT 0;

这样写就是错误的

Syntax error: ‘from’ is not a valid input at this position

这个错误估计是Mysql独有的, 按照SQL的标准,从游标读取数据的语法为

fetch next from cursor_name into variable

我查阅了mysql 官方的document, 上面写的是

FETCH [[NEXT] FROM] cursor_name INTO var_name [, var_name] ...

也就是说可以省略Next From, 然而,在MySQL workbench 6.2 (目前的最新版)中会提示上述错误。改为

fetch cursor_name into variable

后正常。这个是MYSQL WORKBENCH的一个BUG.

遍历表的时候只读出了一条记录(循环提前终止)

按照我们上文的代码,循环终止的条件是Done=1。而
Done变量由一个Handler负责维护,设置的条件是

SQLSTATE '02000'

简单的说,是在查询出错的时候设置变量。若Repeat循环查询过程没出错,则可以正常终止循环。否则,就会因为Repeat内部新查询的出错而提前终止。详细信息可以参考这个官方说明。

解决方法很简单,既然可能在内部出错(我们的例子中某些位置上ANP,VNP可能是空的),我们就在Repeat结束之前手动设置一下。为了保证循环正常终止,把Fetch移动到最后进行。

 set Done=0;
 fetch rs into annoid,fn;
 until Done end repeat;

参考文献&致谢

本文写作过程中得到了很多帮助,下面这些链接中也包含了这个问题的详细解析,供大家参考
* http://www.jbxue.com/db/13432.html
* http://stackoverflow.com/questions/19679594/sql-syntax-error-incorrect-syntax
* http://bugs.mysql.com/bug.php?id=74834
*http://en.wikipedia.org/wiki/Stored_procedure


关于完整代码

完整的代码已经上传在我的Github小项目合集,文件夹名:SQL stored procedure–iterate btw rows中,如果这篇文章侥幸对你有一点帮助,请移步Github帮我点亮一颗星星呗。♥

把海量结果集读得又稳又快:ABAP Open SQL 的 OPEN CURSOR 深度解析与工程实践 SAP游标技术解析:OPEN CURSOR的高效数据管理之道 摘要:本文深入解析SAP系统中OPEN CURSOR技术的核心价值与应用场景。该技术通过将结果集保留在数据库端,使用FETCH分批获取数据,有效解决了全量读取内存溢出与逐行处理性能低下的两难问题。文章详细剖析了游标生命周期管理、WITH HOLD语义的真实限制(仅对Native SQL提交有效)、常见陷阱(如17个游标上限限制)及优化建议。特别强调在超大数据处理、内存敏感场景下的实用价值,并提供了分包处理的最佳实践,帮助开发者在SAP各版本环境中 阅读详情

相关推荐

Workbench使用技巧

Workbench使用技巧

MySQL写注释出现is not valid at this position, expecting ‘)‘错误时的解决方法

错误代码: 出现这种错误的原因是,在括号结束的前面多了一个逗号,去掉就行了 如图 没错了:

m0_46544453的博客 1万+

ROS新手必看:5分钟搞定URDF小车建模(附Rviz可视化调试技巧)

本文为ROS新手提供了快速构建URDF机器人模型的实战指南。通过一个完整的两轮差速小车建模案例,详细解析了URDF的核心语法、Rviz可视化调试技巧以及常见问题排查方法,帮助初学者快速掌握ROS机器人建模与可视化调试的核心技能。

weixin_29079643的博客 250

求问:MySQL出现is not valid at this position, expecting要怎么解决呀

求问各位大佬!

weixin_66278193的博客 3411

Mamba vs YOLO:目标检测选型指南(附实际项目对比)

本文深入对比了Mamba和YOLO在目标检测领域的性能差异与应用场景。通过实际项目数据,分析了两者在城市交通监控、工业质检等场景下的表现,提供了详细的选型指南和部署优化建议,帮助开发者根据实时性、精度等需求选择最适合的解决方案。

weixin_29062255的博客 369

OpenWrt kmod内核不兼容?手把手教你用脚本强制安装驱动模块(附国内镜像源)

本文详细解决了OpenWrt kmod内核不兼容问题,提供智能脚本强制安装驱动模块的方法,并附有国内镜像源加速配置。通过自动化脚本修改内核MD5校验值,确保kmod包正常安装,同时推荐多个国内镜像源以提升下载速度。

weixin_42549451的博客 542

MySQL8.0中的建表语句问题

一 概述 按照MySQL5.7版本格式完成建表之后会一直提示报错,错误如下: 'Student' is not valid at this position,expecting an identifier 不可行的SQL Script create table 'Student' ( 'sid' int(10) primary key auto_increment, 'sname' varchar(16), 'sage' int(10), 'ssex' varchar

calm_encode的博客 5726

Windows 10下用vcpkg一键搞定libcurl开发环境(Code::Blocks 20.03配置指南)

本文详细介绍了在Windows 10系统下使用vcpkg工具快速配置libcurl开发环境的完整指南,特别针对Code::Blocks 20.03 IDE进行优化设置。通过vcpkg自动化管理依赖项,简化libcurl的安装与配置过程,帮助开发者高效搭建网络通信功能开发环境,并提供了常见问题解决方案和实际项目中的最佳实践。

weixin_28040125的博客 250

数据库通关路之存储-游标-视图-索引 数据库技术(五)

创建自定义函数使用语句create function 函数名([变量名1 变量类型1,……,变量名n 变量类型n]) returns 数据类型beginsql语句;return 值;end;删除自定义函数删除自定义函数使用语句drop function 函数名;

爱吃Java的羊的博客 918

电力电子课设救星:用Simulink实现Buck变换器双闭环控制(PID调参技巧)

本文是电力电子课程设计的实用指南,详细讲解如何利用Simulink仿真平台实现Buck变换器的电压电流双闭环控制。文章核心聚焦于PID参数整定的实战技巧,提供了从手动调试口诀到MATLAB脚本自动优化的完整方案,旨在帮助学生高效完成课设,深入理解闭环控制原理并生成专业报告。

weixin_29179311的博客 296

【电源专题】Type-C母座外壳直接接主板GND还是接RC呢?别再纠结了!

Type-C屏蔽壳接地这件事,没有唯一标准答案。符合规范、贴合产品、能过认证,就是最优解。希望这篇文章能帮你理清思路。

一点硬件 601

存储过程理解:开发与运维的双重视角-存储在数据库中的sql脚本

存储过程核心摘要 存储过程是MySQL数据库中的预编译SQL代码块,相当于数据库内部的"脚本方法"。它将多条SQL语句打包成可重复调用的单元,存储在服务器端,一次编译后永久有效。 核心价值: 减少网络传输(只需传输调用命令而非完整SQL) 提升性能(预编译避免重复解析) 保证业务逻辑一致性(集中管理) 增强安全性(通过权限控制访问) 典型应用场景: 高频调用的简单查询(减少SQL拼接) 需要返回计算结果的场景(使用OUT参数) 事务性操作(如订单创建等需要原子性的业务) 批量数据处理(使用游标进行逐行处理)

yuezhilangniao的博客 256

linux系统中实现智能家居的基本方法

使用QT开发智能家居中的一个物联应用,通过云服务器远程控制设备与设备进行通信。在生活中,可以使用WIFI智能插座控制电器开关,比如远程开启热水器,远程打开空调,窗帘等等。包括:WIFI联网,注册到云服务器上,编写QT UI通过网络来与云服务器通信,然后再下发指令到这个连网的设备。硬件说明:需要有一个串口转WIFI模块,另外需要加上一个USB-TTL模块,外加一根T口USB连接线,可接入PC电脑调试。

嵌入式技术开发 2608

SQL与PL/SQL编程精要:从基础查询到存储过程开发(Java开发者数据库能力跃迁指南)

异常名触发条件SELECT INTO 无结果SELECT INTO 返回多行唯一约束冲突除零错误DECLAREBEGINEND IF;🔑关键函数SQLCODE:返回错误码SQLERRM:返回错误信息:抛出自定义错误(-20000 ~ -20999)fill:#333;important;important;fill:none;color:#333;color:#333;important;fill:none;fill:#333;height:1em;是是。

吾为热爱计科,致力于知识分享的践行者,此博客是我在这条道路上留下的足迹。 672

【无人机基站】基于K-mean算法实现无人机基站部署附matlab代码

【无人机基站】基于K-mean算法实现无人机基站部署附matlab代码

天天酷科研的博客 243

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

MySQL存储过程实战:从基础语法到游标、事务与异常处理

存储过程是数据库中的预编译SQL语句集合,它将业务逻辑封装在数据库层,通过一次编写、多处调用的方式提升代码复用性。其核心原理是将复杂的SQL操作和流程控制(如条件判断、循环)组织成可调用的单元,减少了应用层与数据库之间的网络交互次数,从而提升执行效率。在技术价值上,存储过程特别适用于处理数据密集型任务,如复杂报表生成、ETL流程和批量数据处理,能够有效降低网络开销并保证数据操作的原子性。应用场景包括高频数据操作、历史数据迁移以及对性能敏感的核心计算任务。本文以MySQL存储过程为例,详细解析了其创建、调用、

weixin_34252090的博客 388

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

【前端视野下的数据库概念探秘】——信息化人员必备知识&面试宝典:解码“视图”与“游标”

视图与游标,作为数据库领域的两大利器,虽藏于幕后,却对前端应用的性能和体验有着间接却深远的影响。作为前端开发者,理解这些概念,不仅能增进与后端团队的沟通,更能指导我们在设计数据获取策略时做出更明智的选择。你是否在实际项目中遇到过因视图或游标使用不当引发的问题?又或是有巧妙运用它们的成功案例?欢迎在评论区分享你的故事,一起交流成长,共同探索更高效、安全的前端开发之道。欢迎来到我的博客,很高兴能够在这里和您见面!

一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身"农奴"把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟! 1229

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

oracle sql 子游标_Oracle 父子游标

Oracle 父子游标[编辑]游标从Oracle数据库管理员的角度上说,游标是对存储在库缓存中的可执行对象的统称。SQL语句是存储在库缓存中的,它是游标。除了它之外,还有Oracle的存储过程也是存储在库缓存中的可执行对象,从Oracle DBA的角度上说,它也是游标。Oracle也把它算为游标,在某些和游标相关的视图中,也会显示存储过程的一些信息的。但从开发者的角度说,只有SQL语句才是游标。子...

weixin_39845613的博客 120

PostgreSQL游标与函数深度解析:数据库流式处理与逻辑封装实战

在数据库系统中,游标(Cursors)和函数(Functions)是处理复杂数据流和实现业务逻辑封装的核心基础组件。游标提供了对查询结果集的逐行或分批访问能力,本质上是一种惰性求值机制,能够有效管理内存并支持流式数据处理。函数则作为数据库逻辑的容器,通过封装SQL和流程控制,对外提供简洁的接口。两者的技术价值在于将计算贴近存储,减少不必要的数据网络传输,优化资源利用,并提升复杂业务逻辑的执行效率。在应用场景上,这种组合特别适用于报表生成、批量数据迁移、ETL流程以及需要逐行计算的复杂业务规则等场景。本文聚焦

weixin_30435261的博客 715

维护索引、游标使用、创建视图、触发器、事务、存储过程

维护索引、游标使用、创建视图、触发器、事务、存储过程

阿牛哥的博客 873

浅析Oracle共享SQL区、私有SQL区与游标

问题引出: OCP 11g052 第15题 15、Which two statements are true about Shared SQL Area and Private SQL Area? (Choose ...

cuixu4010的博客 664

MySQL存储过程开发

最后,它提高了代码复用性,同一存储过程可被多个应用调用,确保业务逻辑的一致性。在当今数据驱动的商业环境中,数据库不仅仅是静态存储容器,更是业务逻辑的核心载体。未来,存储过程将继续在数据密集型应用中扮演重要角色,但它的使用将更加精细化、专业化,成为数据架构师工具箱中的一件精密工具,而非解决所有问题的万能钥匙。存储过程本质上是一组预编译的SQL语句集合,存储在数据库服务器中,可通过名称调用执行。与传统分散的SQL脚本相比,存储过程将数据操作逻辑封装在数据库内部,形成了独立于应用程序的数据处理单元。

puaseo_281的博客 147

(十一)视图、游标

视图 视图是一种虚拟的表,具有和物理表相同的功能,可以对视图进行增,删,改,查等操作。特别地,对视图的修改不影响基本表。相比多表查询,它使得我们获取数据更容易。 视图作用 ①简化数据查询语句 ②可以使用户能从多视角看待同一数据 ③提高数据的安全性 游标 游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录进行处理的机制。 游标的使用步骤: 定义游标:decl...

FixedStar 的博客 268
上一篇: 批量复制文件-matlab实现
下一篇: 数据可视化上集:使用Gliffy,ProcessOn迅速绘制论文中的流程图,系统结构图
ColdZoo
博客等级 码龄12年 4粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值