使用WHILE代替游标的遍历操作

本文对比了使用游标和While循环遍历数据的方法,并提供了具体的SQL实现案例。通过两种方式的对比,说明了While循环相较于游标在减少锁竞争及避免死锁方面的优势。
         游标操作会锁住被遍历的表,容易引起死锁,应当尽量避免使用。

原游标代码:
None.gif    DECLARE @tbTargetPermissions    table(TargetPermissionId uniqueidentifier NOT NULL PRIMARY KEY)
None.gif    
INSERT INTO @tbTargetPermissions 
None.gif        
SELECT [TargetPermissionId] 
None.gif        
FROM [ps_RolePermissions] 
None.gif        
WHERE [TargetId] = @TargetId AND [RoleId] = @RoleId
None.gif    
None.gif    
DECLARE @TargetPermissionId uniqueidentifier;
None.gif
None.gif    
--定义游标
None.gif
    DECLARE TargetPermissions_ByRoleId_Cursor CURSOR FOR 
None.gif        
SELECT [TargetPermissionId] FROM @tbTargetPermissions 
None.gif
None.gif    
--打开游标
None.gif
    OPEN TargetPermissions_ByRoleId_Cursor
None.gif
None.gif    
--读取游标第一条记录
None.gif
    FETCH NEXT FROM    TargetPermissions_ByRoleId_Cursor INTO @TargetPermissionId
None.gif
None.gif    
--检查@@FETCH_STATUS的值,以便进行循环读取
None.gif
    WHILE @@FETCH_STATUS = 0
None.gif    
BEGIN
None.gif        
EXEC ps_TargetPermissionEntity_Select @TargetPermissionId;
None.gif
None.gif        
FETCH NEXT FROM    TargetPermissions_ByRoleId_Cursor INTO @TargetPermissionId;
None.gif    
END
None.gif
None.gif    
--关闭游标
None.gif
    CLOSE TargetPermissions_ByRoleId_Cursor
None.gif    
DEALLOCATE TargetPermissions_ByRoleId_Cursor

改用While后仍然可以遍历执行存储过程 ps_TargetPermissionEntity_Select
None.gif    --把合符条件的目标权限Id加载到一个临时表变量中
None.gif
    DECLARE @tbTargetPermissions    table(IndexId int IDENTITY (01NOT NULL PRIMARY KEY, TargetPermissionId uniqueidentifier NOT NULL)
None.gif    
INSERT INTO @tbTargetPermissions 
None.gif        
SELECT [TargetPermissionId] 
None.gif        
FROM [ps_RolePermissions] 
None.gif        
WHERE [TargetId] = @TargetId AND [RoleId] = @RoleId
None.gif
None.gif    
DECLARE @MaxIndexId int;
None.gif    
SELECT  @MaxIndexId = MAX([IndexId]FROM @tbTargetPermissions--计算最大记录序号,用于遍历列表
None.gif

None.gif    
WHILE @MaxIndexId > -1
None.gif    
BEGIN
None.gif        
DECLARE @TargetPermissionId uniqueidentifier;
None.gif        
SELECT @TargetPermissionId = [TargetPermissionId] FROM @tbTargetPermissions WHERE [IndexId] = @MaxIndexId;
None.gif
None.gif        
EXEC ps_TargetPermissionEntity_Select @TargetPermissionId;
None.gif
None.gif        
--删除最大记录项,重新判断记录项是否大于-1,以此判断是否遍历完列表
None.gif
        DELETE @tbTargetPermissions WHERE [IndexId] = @MaxIndexId;
None.gif        
SELECT  @MaxIndexId = MAX([IndexId]FROM @tbTargetPermissions 
None.gif        
--SELECT @MaxIndexId--测试(倒序)
None.gif
    END

执行效果相同,就是这里的while与上一方法的排序是相反的,如果对排序顺序有要求的,可以改变一下算法。
按顺序排列的代码如下:
None.gif    --把合符条件的目标权限Id加载到一个临时表变量中
None.gif
    DECLARE @tbTargetPermissions    table(IndexId int IDENTITY (01NOT NULL PRIMARY KEY, TargetPermissionId uniqueidentifier NOT NULL)
None.gif    
INSERT INTO @tbTargetPermissions 
None.gif        
SELECT [TargetPermissionId] 
None.gif        
FROM [ps_RolePermissions] 
None.gif        
WHERE [TargetId] = @TargetId AND [RoleId] = @RoleId
None.gif
None.gif    
DECLARE @MinIndexId int;
None.gif    
DECLARE @MaxIndexId int;
None.gif    
SELECT  @MinIndexId = MIN([IndexId]FROM @tbTargetPermissions--计算最小记录序号,用于遍历列表
None.gif
    SELECT  @MaxIndexId = MAX([IndexId]FROM @tbTargetPermissions--计算最大记录序号,用于遍历列表
None.gif

None.gif    
WHILE @MinIndexId <= @MaxIndexId
None.gif    
BEGIN
None.gif        
--SELECT @MinIndexId,@MaxIndexId--测试(顺序)
None.gif
        DECLARE @TargetPermissionId uniqueidentifier;
None.gif        
SELECT @TargetPermissionId = [TargetPermissionId] FROM @tbTargetPermissions WHERE [IndexId] = @MinIndexId;
None.gif
None.gif        
EXEC ps_TargetPermissionEntity_Select @TargetPermissionId;
None.gif
None.gif        
--删除最小记录项,重新判断最小记录项是否小于等于最大记录项,以此判断是否遍历完列表
None.gif
        DELETE @tbTargetPermissions WHERE [IndexId] = @MinIndexId;
None.gif        
SELECT  @MinIndexId = MIN([IndexId]FROM @tbTargetPermissions
None.gif    
END

转载于:https://www.cnblogs.com/chenjunbiao/archive/2007/03/27/1760240.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值