如何避免光标和另一种方式是什么?

时间:2013-07-24 17:46:03

标签: sql sql-server sql-server-2008 sqlite

我在我的存储过程中使用光标;我希望从我的SP中删除光标。请帮我提出一个解决方案,用于避免使用dynamic将光标语句恢复为正常更新语句。

以下示例:

  1. Update Tablename set columnname(variable) = value from table A join Table B on A.condition = B.Condition where name = 'Test'(variable) and age = 18(variable)

  2. Update Tablename set columnname(variable) = value from table A join Table B on A.condition = B.Condition where name = 'kumar'(variable) and age = 19(variable)

  3. Update Tablename set columnname(variable) = value from table A join Table B on A.condition = B.Condition where name = 'babu'(variable) and age = 30(variable)

  4. 这就是我的光标的工作方式。 300组合动态选择表中的数据并更新到主表

    我正在尝试取出游标,并且update语句应该与此类似,而不是编写300个更新语句,我想编写一个更新,其中所有300个组合应该执行。

    以下是需要此解决方案的代码:

    BEGIN
      DECLARE @Type VARCHAR(100)           
      DECLARE @TargetColumn VARCHAR(100)           
      DECLARE @SourceColumn VARCHAR(100)           
      DECLARE @SQL varchar(max)        
    
      DECLARE a_cursor CURSOR STATIC           
      FOR          
      SELECT [Type],[SourceColumn],[TargetColumn] FROM  ref.tblEdsMap        
      GROUP BY [Type],[SourceColumn],[TargetColumn]         
      OPEN a_cursor          
      FETCH NEXT FROM a_cursor INTO @Type,@SourceColumn,@TargetColumn      
      WHILE @@FETCH_STATUS = 0          
      BEGIN          
    
    
      SET @SQL = 'UPDATE  GCT SET GCT.' + @TargetColumn + ' = map.[TargetValue]       
       from  EdsMap map      
       JOIN Table GCT      
       ON GCT.' + @SourceColumn + ' = map.[SourceValue]       
       where map.[Type]=''' + @Type + ''' and map.SourceColumn=''' + @SourceColumn+ ''''       
      Exec (@SQL)        
      PRINT @SQL        
      FETCH NEXT FROM a_cursor INTO @Type,@SourceColumn,@TargetColumn      
      END          
      CLOSE a_cursor          
      DEALLOCATE a_cursor       
    END
    

3 个答案:

答案 0 :(得分:1)

我没有使用明确的游标或光标巧妙地伪装成while循环,而是更倾向于对这类问题进行行级联操作。

DECLARE @cmd NVARCHAR(MAX) = N'';

SELECT @cmd += N'
   UPDATE GCT 
     SET GCT.' + QUOTENAME(TargetColumn) + ' = map.TargetValue     
     FROM dbo.EdsMap AS map 
     INNER JOIN dbo.Table AS GCT      
     ON GCT.' + QUOTENAME(SourceColumn) + ' = map.SourceValue    
   WHERE map.[Type] = ''' + [Type] + ''' 
   AND map.SourceColumn = ''' + [SourceColumn]+ ''';'
FROM ref.tblEdsMap
GROUP BY [Type], SourceColumn, TargetColumn;

EXEC sp_executesql @sql;

答案 1 :(得分:0)

当我在过去完成这些操作时,我通常会编写一个事务来包含所需的每个更新。像这样:

    CREATE TABLE #targets ([Type] VARCHAR(255),[SourceColumn] VARCHAR(255),[TargetColumn] VARCHAR(255));

    INSERT INTO #targets
            ( [Type], [SourceColumn], [TargetColumn] )       
    SELECT [Type],[SourceColumn],[TargetColumn] FROM  ref.tblEdsMap        
      GROUP BY [Type],[SourceColumn],[TargetColumn]; 

    DECLARE @sql VARCHAR(MAX);

    SET @sql = 'BEGIN TRAN'  + CHAR(10) + CHAR(13);

    SELECT @sql = @sql + 
    'UPDATE  GCT SET GCT.' + [TargetColumn] + ' = map.[TargetValue]       
       from  EdsMap map      
       JOIN Table GCT      
       ON GCT.' + [SourceColumn] + ' = map.[SourceValue]       
       where map.[Type]=''' + [Type] + ''' and map.SourceColumn=''' + [SourceColumn]+ ''';' + CHAR(10) + CHAR(13)
    FROM #targets   

    SELECT @sql = @sql + 'COMMIT TRAN'

    PRINT @sql

    Exec (@SQL) 

更新语句仍然相同,即每个组合获得一次更新。但现在您作为一个交易批次运行。您可能会对动态SQL更有兴趣,因此您只有一个更新语句,但根据我的经验,以这种方式获取不良更新太容易了。

这样做可能不会比光标快。你必须测试才能确定。通过我使用这种方法的示例, 通常是一种更快的方法。

答案 2 :(得分:-2)

尝试使用表变量和WHILE循环,如下所示:

 BEGIN

 DECLARE @Type VARCHAR(100)           
 DECLARE @TargetColumn VARCHAR(100)           
 DECLARE @SourceColumn VARCHAR(100)           
 DECLARE @SQL varchar(max)        

 DECLARE @SomeTable TABLE
 (
   ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL,
   Type varchar(100),
   SourceColumn varchar(100),
   TargetColumn varchar(100)
 )

 DECLARE @Count int, @Max int

 INSERT INTO @SomeTable (Type, SourceColumn, TargetColumn)
 SELECT [Type],[SourceColumn],[TargetColumn]
 FROM  ref.tblEdsMap        
 GROUP BY [Type],[SourceColumn],[TargetColumn]

 SELECT @Count = 1, @Max = COUNT(ID)
 FROM @SomeTable

 WHILE @Count <= @Max
 BEGIN

   SELECT
        @Type = Type, 
        @SourceColumn = SourceColumn, 
        @TargetColumn = TargetColumn
   FROM @SomeTable
   WHERE ID = @Count  

   -- Your code
   SET @SQL = 'UPDATE  GCT SET GCT.' + @TargetColumn + ' = map.[TargetValue]       
   from  EdsMap map      
   JOIN Table GCT      
   ON GCT.' + @SourceColumn + ' = map.[SourceValue]       
   where map.[Type]=''' + @Type + ''' and map.SourceColumn=''' + @SourceColumn+ ''''       
   Exec (@SQL)        
   PRINT @SQL        

   SET @Count = @Count + 1

 END     -- while

 END