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

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

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

DECLARE
@A1 VARCHAR(10),
@A2 VARCHAR(10),
@A3 INT
DECLARE CURSOR YOUCURNAME FOR SELECT A1,A2,A3 FROM YOUTABLENAME
OPEN YOUCURNAME
fetch next from youcurname into @a1,@a2,@a3
while @@fetch_status<>-1
begin
update … set …-a3 where …

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

fetch next from youcurname into @a1,@a2,@a3
end
close youcurname
deallocate youcurname

—————————————

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

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

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

Create PROCEDURE P_InsertSubject
@SubjectId int
AS
DECLARE rs CURSOR LOCAL SCROLL FOR
select studentid from student where StudentGradu = 1
OPEN rs
FETCH NEXT FROM rs INTO @tempStudentID
WHILE @@FETCH_STATUS = 0
BEGIN
Insert SelSubject values (@SubjectId,@tempStudentID)
FETCH NEXT FROM rs INTO @tempStudentID
END
CLOSE rs
GO

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

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

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

Create PROCEDURE P_InsertSubject
@SubjectId int
AS
declare @i int,
@studentid
DECLARE @tCanStudent TABLE
(
studentid int
,FlagID TINYINT
)
BEGIN
insert @tCanStudent select studentid,0 from student where StudentGradu = 1
SET @i=1
WHILE( @i>=1)
BEGIN
SELECT @studentid=''
SELECT TOP 1 @studentid = studentid FROM @tCanStudent WHERE flagID=0
SET @i=@@ROWCOUNT
IF @i<=0 GOTO Return_Lab
Insert SelSubject values (@SubjectId,@studentid)
IF @@error=0
UPDATE @tCanStudent SET flagID=1 WHERE studentid = @studentid
Return_Lab:
END
End
GO

我们现在再来分析以上这个存储过程,它实现的方法是先把满足条件的记录集数据存放到一个表变量中,并且在这个表变量中增加一个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 int
set @i=1
while @i<30
begin
insert into test (userid) values(@i)
set @i=@i+1
end

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

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

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

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

USE pubs
GO
WHILE (SELECT AVG(price) FROM titles) < $30
BEGIN
  UPDATE titles
  SET price = price * 2
  SELECT MAX(price) FROM titles
  IF (SELECT MAX(price) FROM titles) > $50
  BREAK
  ELSE
  CONTINUE
END
PRINT 'Too much for the market to bear'

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

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

单变量循环

USE pubs
DECLARE tnames_cursor CURSOR
FOR
  SELECT TABLE_NAME
  FROM INFORMATION_SCHEMA.TABLES
OPEN tnames_cursor
DECLARE @tablename sysname
--SET @tablename = 'authors'
FETCH NEXT FROM tnames_cursor INTO @tablename
WHILE (@@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 @tablename
END
CLOSE tnames_cursor
DEALLOCATE tnames_cursor

多变量循环

CREATE  PROCEDURE my_FeeCount AS
declare @到期时间  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_data
fetch 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 @到期时间,@片区,@缴费用户数
end
close 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 再执行他一下。

(0)

相关推荐

  • Mysql存储过程循环内嵌套使用游标示例代码

    BEGIN -- 声明变量 DECLARE v_addtime_begin varchar(13); DECLARE v_addtime_end varchar(13); DECLARE v_borrow_id int; DECLARE v_count int; DECLARE s1 int; /** 声明游标,并将查询结果存到游标中 **/ DECLARE c_borrow CURSOR FOR SELECT ID from rocky_borrow WHERE BORROWTYPE = 2

  • MySQL存储过程中游标循环的跳出和继续操作示例

    最近遇到这样的问题,在MySQL的存储过程中,游标操作时,需要执行一个conitnue的操作.众所周知,MySQL中的游标循环操作常用的有三种,LOOP,REPEAT,WHILE.三种循环,方式大同小异.以前从没用过,所以记下来,方便以后查阅. 1.REPEAT 复制代码 代码如下: REPEAT     Statements;   UNTIL expression END REPEAT demo DECLARE num INT; DECLARE my_string  VARCHAR(255);

  • mysql存储过程 游标 循环使用介绍

    Mysql的存储过程是从版本5才开始支持的,所以目前一般使用的都可以用到存储过程.今天分享下自己对于Mysql存储过程的认识与了解. 一些简单的调用以及语法规则这里就不在赘述,网上有许多例子.这里主要说说大家常用的游标加循环的嵌套使用. 首先先介绍循环的分类: (1)WHILE ... END WHILE (2)LOOP ... END LOOP (3)REPEAT ... END REPEAT (4)GOTO 这里有三种标准的循环方式:WHILE循环,LOOP循环以及REPEAT循环.还有一种

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

    用游标,和WHILE可以遍历您的查询中的每一条记录并将要求的字段传给变量进行相应的处理 ================== DECLARE @A1 VARCHAR(10), @A2 VARCHAR(10), @A3 INT DECLARE CURSOR YOUCURNAME FOR SELECT A1,A2,A3 FROM YOUTABLENAME OPEN YOUCURNAME fetch next from youcurname into @a1,@a2,@a3 while @@fetch

  • SQL Server 游标语句 声明/打开/循环实例

    SQL Server游标语句使用方法: 复制代码 代码如下: --声明一个游标 DECLARE MyCursor CURSOR FOR SELECT TOP 5 FBookName,FBookCoding FROM TBookInfo//定义一个叫MyCursor的游标,存放for select 后的数据 --打开一个游标 OPEN MyCursor//即打开这个数据集 --循环一个游标 DECLARE @BookName nvarchar(2000),@BookCoding nvarchar(

  • SQL Server时间戳功能与用法详解

    本文实例讲述了SQL Server时间戳功能与用法.分享给大家供大家参考,具体如下: 一直对时间戳这个概念比较模糊,相信有很多朋友也都会误认为:时间戳是一个时间字段,每次增加数据时,填入当前的时间值.其实这误导了很多朋友. 1.基本概念 时间戳:数据库中自动生成的唯一二进制数字,与时间和日期无关的, 通常用作给表行加版本戳的机制.存储大小为 8个字节. 每个数据库都有一个计数器,当对数据库中包含 timestamp 列的表执行插入或更新操作时,该计数器值就会增加.该计数器是数据库时间戳.这 可以

  • SQL Server触发器和事务用法示例

    本文实例讲述了SQL Server触发器和事务用法.分享给大家供大家参考,具体如下: 新增和删除触发器 alter trigger tri_TC on t_c for INSERT,delete as begin set XACT_ABORT ON declare @INSERTCOUNT int; declare @DELETECOUNT int; declare @UPDATECOUNT int; set @INSERTCOUNT = (select COUNT(*) from insert

  • SQL利用游标遍历日期查询的过程详解

    需求:我有个存储过程,每次执行需要带入一个连续的日期.我想遍历执行出一个月的时间,怎么搞? 我本来的想法是:程序里面写一个for循环,循环里面循环传日期去执行这个存储过程. 但是同事告诉我用游标,我从来没用过,就尝试了一下,没想到成功了哈哈,记录一下! -- 1.声明游标变量 declare @begin_date varchar(50), @sumWeight varchar(50) -- 2.声明游标 declare date_cursor cursor for -- date_cursor

  • SQL Server 中 RAISERROR 的用法详细介绍

    SQL Server 中 RAISERROR 的用法 raiserror 的作用: raiserror 是用于抛出一个错误.[ 以下资料来源于sql server 2005的帮助 ] 其语法如下: RAISERROR ( { msg_id | msg_str | @local_variable } { ,severity ,state } [ ,argument [ ,...n ] ] ) [ WITH option [ ,...n ] ] 简要说明一下: 第一个参数:{ msg_id | ms

  • sql存储过程实例--动态根据表数据复制一个表的数据到另一个表

    动态根据表数据复制一个表的数据到另一个表 把track表的记录 根据mac_id后两位数字,复制到对应track_? 的表中 如:mac_id=12345678910,则后两位10 对应表为track_10,就把此记录复制到track_10中 创建一个 sub_track的存储过程实现: -- 创建一个 名为sub_track的存储过程 CREATE PROCEDURE sub_track() begin declare i int; -- 定义 循环变量i set @imei =0; -- 定

  • SQL 存储过程基础语法之一

    CREATE PROCEDURE 创建存储过程,存储过程是保存起来的可以接受和返回用户提供的参数的 Transact-SQL 语句的集合. 可以创建一个过程供永久使用,或在一个会话中临时使用(局部临时过程),或在所有会话中临时使用(全局临时过程).也可以创建在 Microsoft? SQL Server? 启动时自动运行的存储过程. 语法 CREATE PROC [ EDURE ] procedure_name [ ; number ] [ { @parameter data_type } [

  • Oracle存储过程游标用法分析

    本文实例讲述了Oracle存储过程游标用法.分享给大家供大家参考,具体如下: 使用游标的5个步骤 1.声明一些变量用于保存select语句返回的指 2.声明游标,并指定select 语句 3.打开游标 4.从游标中获取记录 5.关闭游标 从游标中获取每一条记录可使用fetch语句.fetch语句将列的指读取到指定的变量中: 语法: fetch cursor_name into variable[, variable ...]; 例子: create or replace procedure se

随机推荐