侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Sql存储过程游标循环的用法及sql如何使用cursor写一个简单的循环

数据库  /  管理员 发布于 5年前   277

用游标,和WHILE可以遍历您的查询中的每一条记录并将要求的字段传给变量进行相应的处理

==================

DECLARE @A1 VARCHAR(10),@A2 VARCHAR(10),@A3 INTDECLARE CURSOR YOUCURNAME FOR SELECT A1,A2,A3 FROM YOUTABLENAMEOPEN YOUCURNAMEfetch next from youcurname into @a1,@a2,@a3while @@fetch_status<>-1beginupdate … set …-a3 where …

……您要执行的操作写在这里

fetch next from youcurname into @a1,@a2,@a3endclose youcurnamedeallocate youcurname

―――――――――――――

在应用程序开发的时候,我们经常可能会遇到下面的应用,我们会通过查询数据表的记录集,循环每一条记录,通过每一条的记录集对另一张表进行数据进行操作,如插入与更新,我们现在假设有一个这样的业务:老师为所在班级的学生选课,选的课程如有哲学、马克思主义政治经济学、毛泽东思想概论、邓小平理论这些课,现在操作主要如下:

1) 先要查询这些还没有毕业的这些学生的名单,毕业过后的无法进行选课;
2) 在批量的选取学生的同时,还需要添加对应的某一门课程;
3) 点添加后选课结束。

数据量少可能看不出用Java程序直接多次进行数据库操作这种办法实现的弱点,因为它每次在操作数据库的时候,都存在着频繁的和数据库的I/O直接交互,这点性能的牺牲实属不应该,那我们就看下面的方法,通过存储过程的游标方法来实现:建立存储过程:

Create PROCEDURE P_InsertSubject@SubjectId intASDECLARE rs CURSOR LOCAL SCROLL FORselect studentid from student where StudentGradu = 1OPEN rsFETCH NEXT FROM rs INTO @tempStudentIDWHILE @@FETCH_STATUS = 0BEGINInsert SelSubject values (@SubjectId,@tempStudentID)FETCH NEXT FROM rs INTO @tempStudentIDENDCLOSE rsGO

使用游标对记录集循环进行处理的时候一般操作如以下几个步骤:

1、把记录集传给游标;
2、打开游标
3、开始循环
4、从游标中取值
5、检查那一行被返回
6、处理
7、关闭循环
8、关闭游标

上面这种方法在性能上面无疑已经是提高很多了,但我们也想到,在存储过程编写的时候,有时候我们尽量少的避免使用游标来进行操作,所以我们还可以对上面的存储过程进行改造,使用下面的方法来实现:

Create PROCEDURE P_InsertSubject@SubjectId intASdeclare @i int,@studentidDECLARE @tCanStudent TABLE(studentid int,FlagID TINYINT)BEGINinsert @tCanStudent select studentid,0 from student where StudentGradu = 1SET @i=1WHILE( @i>=1)BEGINSELECT @studentid=''SELECT TOP 1 @studentid = studentid FROM @tCanStudent WHERE flagID=0SET @i=@@ROWCOUNTIF @i<=0 GOTO Return_LabInsert SelSubject values (@SubjectId,@studentid)IF @@error=0UPDATE @tCanStudent SET flagID=1 WHERE studentid = @studentidReturn_Lab:ENDEndGO

我们现在再来分析以上这个存储过程,它实现的方法是先把满足条件的记录集数据存放到一个表变量中,并且在这个表变量中增加一个FLAGID进行数据初始值为0的存放,然后去循环这个记录集,每循环一次,就把对应的FLAGID的值改成1,然后再根据循环来查找满足条件等于0的情况,可以看到,每循环一次,处理的记录集就会少一次,然后循环的往选好课程表里面插入,直到记录集的条数为0时停止循环,此时完成操作。

比较以上的几种循环方法的应用,就会知道,有时候可能对于同一种功能我们实现的方法不同,而最终应用程序性能的影响的差异就会很大,第二种、第三种就大大的减少的数据库交互I/O操作的频繁,会节省很多时间,方法三又避免用游标又可以节省不必要的开销。

使用SQL的Agent可以执行计划任务,把写好的SQL语句放在计划任务里,可以达到奇妙的效果,如定时备份数据,定时执行特定操作等等,当涉及循环操作很多条数据时,这里就要使用游标了,当然SQL中也有循环语句,如使用While。不过while的功能只能实现一般的操作,游标的功能更为强大些,可在一个指定的一个集合内循环操作数据,实现动态操作,那就更牛了,呵呵,以下资料供存档用。

WHILE

设置重复执行 SQL 语句或语句块的条件。只要指定的条件为真,就重复执行语句。可以使用 BREAK 和 CONTINUE 关键字在循环内部控制 WHILE 循环中语句的执行。

语法

WHILE Boolean_expression  { sql_statement | statement_block }  [ BREAK ]  { sql_statement | statement_block }  [ CONTINUE ]

参数

Boolean_expression

返回 TRUE 或 FALSE 的表达式。如果布尔表达式中含有 SELECT 语句,必须用圆括号将 SELECT 语句括起来。

复制代码 代码如下:
{sql_statement | statement_block}

Transact-SQL 语句或用语句块定义的语句分组。若要定义语句块,请使用控制流关键字 BEGIN 和 END。

BREAK

导致从最内层的 WHILE 循环中退出。将执行出现在 END 关键字后面的任何语句,END 关键字为循环结束标记。

CONTINUE

使 WHILE 循环重新开始执行,忽略 CONTINUE 关键字后的任何语句。

注释

如果嵌套了两个或多个 WHILE 循环,内层的 BREAK 将导致退出到下一个外层循环。首先运行内层循环结束之后的所有语句,然后下一个外层循环重新开始执行。

示例

declare @i intset @i=1while @i<30begininsert into test (userid) values(@i)set @i=@i+1end

------------------------------------------------------------

while 条件begin执行操作set @i=@i+1end

A. 在嵌套的 IF...ELSE 和 WHILE 中使用 BREAK 和 CONTINUE

在下例中,如果平均价格少于 $30,WHILE 循环就将价格加倍,然后选择最高价。如果最高价少于或等于 $50,WHILE 循环重新启动并再次将价格加倍。该循环不断地将价格加倍直到最高价格超过 $50,然后退出 WHILE 循环并打印一条消息。

USE pubsGOWHILE (SELECT AVG(price) FROM titles) < $30BEGIN  UPDATE titles  SET price = price * 2  SELECT MAX(price) FROM titles  IF (SELECT MAX(price) FROM titles) > $50  BREAK  ELSE  CONTINUEENDPRINT 'Too much for the market to bear'

B. 在带有游标的过程中使用 WHILE

以下的 WHILE 结构是名为 count_all_rows 过程中的一部分。下例中,该 WHILE 结构测试用于游标的函数 @@FETCH_STATUS 的返回值。因为 @@FETCH_STATUS 可能返回 C2、-1 或 0,所以,所有的情况都应进行测试。如果某一行在开始执行此存储过程以后从游标结果中删除,将跳过该行。成功提取 (0) 后将执行 BEGIN...END 循环内部的 SELECT 语句。

单变量循环

USE pubsDECLARE tnames_cursor CURSORFOR  SELECT TABLE_NAME   FROM INFORMATION_SCHEMA.TABLESOPEN tnames_cursorDECLARE @tablename sysname--SET @tablename = 'authors'FETCH NEXT FROM tnames_cursor INTO @tablenameWHILE (@@FETCH_STATUS <> -1)BEGIN  IF (@@FETCH_STATUS <> -2)  BEGIN   SELECT @tablename = RTRIM(@tablename)   EXEC ('SELECT ''' + @tablename + ''' = count(*) FROM '     + @tablename )  PRINT ' ' END  FETCH NEXT FROM tnames_cursor INTO @tablenameENDCLOSE tnames_cursorDEALLOCATE tnames_cursor

多变量循环

CREATE  PROCEDURE my_FeeCount ASdeclare @到期时间  char(10)declare @片区   char(20)declare @缴费用户数 char(10)declare @sql char(2000)declare cur_data cursor for  select convert(varchar(10),到期时间,120) as 到期时间 ,片区,count(distinct main_id) as 缴费用户数  from V_aipu_fee where 提交时间>=convert(varchar(10),getdate()-90,120) and 提交时间<convert(varchar(10),getdate()+1-90,120) and 收费类型='续费收费' Group by convert(varchar(10),到期时间,120),片区 order by convert(varchar(10),到期时间,120) open cur_datafetch next from cur_data into @到期时间,@片区,@缴费用户数 while(@@fetch_status = 0) begin  set @sql='update '+RTRIM(@片区)+'实收='+RTRIM(@片区)+'实收+'+RTRIM(@缴费用户数)+' where 收费日期='''+RTRIM(@到期时间)+'''' print @sql fetch next from cur_data into @到期时间,@片区,@缴费用户数 endclose cur_data

下面接着给大家介绍sql使用cursor写一个简单的循环

1.排错

  和sql server较了一天的劲,只写了两个简单的存储过程。当然智商虽然不高还没低到这个份上。大半天都是花费在排错上了。

  System.Data.SqlClient.SqlException: SQL Server 不存在或访问被拒绝。 at

System.Data.SqlClient.ConnectionPool.GetConnection(Boolean& isInTransaction) at System.Data.SqlClient.SqlConnectionPoolManager.GetPooledConnection(SqlConnectionString options, Boolean& isInTransaction) at System.Data.SqlClient.SqlConnection.Open() at _20060409.WebForm1.test() in d:\work files\20060409\webform1.aspx.cs:line 52

  冷不丁报了这个错,这个就是从程序里连不上。在服务中除了MSSQLserverADHelper以外所有的服务都打开了还是不行;名称正确、无别名、没起实例名称;端口号服务器端和客户端都是1433。为了找出问题只好上网查查结果发现连上网线后这个毛病就没了。晕,看来是少打了什么补丁。

2.写循环

  首先需求是这样的我手里现在有两张表,rights和roles。

  表结构如下:

rights  -------------------  rightid int  right varchar(20)    ==========    roles  -------------------  roleid int  roletype int  role varchar(20)  rightid int

    在我的role表里有一个角色admin。admin拥有right表中的所有权限,但是有四个字段,要是用手写完我这个速度,加上这个数量我看也就算了。省了手上的力气就要费脑子。

  在查询分析器里写了半天,总算是吭哧出来了。

  首先使用truncate table把role原来的失败信息清掉,听说会比delete快一点,只不过数量少看不出明显效果。

  然后建立一个临时的用于填充的存储过程。

create procedure TempFill    declare mycursor cursor for  select rightid from rights--这两个是一句,定义游标,然后从rights中取一个rightid给游标    open mycursor    declare @rightid int--定义一个变量  fetch mycursor into @rightid--把mycursor当前的值给@rightid    while @@fetch_status=  begin  insert into rolestable (roletype,role,rightid)values(,'admin',@rightid)  fetch mycursor into @rightid  end    close mycursor  deallocate mycursor

  这样就写完了。

  execute TempFill 再执行他一下。


  • 上一条:
    SqlDateTime溢出该怎么解决
    下一条:
    SQL Server 表变量和临时表的区别(详细补充篇)
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 分库分表的目的、优缺点及具体实现方式介绍(0个评论)
    • DevDB - 在 VS 代码中直接访问数据库(0个评论)
    • 在ubuntu系统中实现mysql数据存储目录迁移流程步骤(0个评论)
    • 在mysql中使用存储过程批量新增测试数据流程步骤(0个评论)
    • php+mysql数据库批量根据条件快速更新、连表更新sql实现(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-06
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-01
    • 2018-05
    • 2018-10
    • 2018-11
    • 2020-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2021-02
    • 2021-04
    • 2021-07
    • 2021-08
    • 2021-11
    • 2021-12
    • 2022-02
    • 2022-03
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客