在SQL中避免光标

时间:2009-08-26 04:25:07

标签: sql-server cursor

如果遇到性能问题,在SQL中使用游标的最佳替代方法是什么?

我得到了以下代码,其中它使用Cursor循环并插入记录。

      DECLARE @AuditBatchID_logRow INT,
    @AuditOperationID_logRow INT,
    @RowIdentifier_logRow nvarchar(200),
    @AuditDBTableID_logRow INT, 
    @AuditLogRowID INT,

    @AuditDBColumnID INT, 
    @NewValue nvarchar(200),
    @PreviousVaue nvarchar(200), 
    @NewDisplayValue nvarchar(200)

  DECLARE Crsr_AUDITLOGROW CURSOR LOCAL FORWARD_ONLY STATIC 
      FOR 
         SELECT [t0].[AuditBatchID], 
                [t1].[AuditOperationID], 
                [t1].[RowIdentifier],
                [t0].[AuditTableID],
                [t1].[AuditLogRowID]
         FROM [AuditBatchTable] AS [t0]
         INNER JOIN [AuditLogRow] AS [t1] 
               ON [t0].[AuditBatchTableID] = [t1].[AuditBatchTableID]

  Open Crsr_AUDITLOGROW

  FETCH NEXT FROM Crsr_AUDITLOGROW 
     INTO @AuditBatchID_logRow, 
          @AuditOperationID_logRow,  
          @RowIdentifier_logRow, 
          @AuditDBTableID_logRow,
          @AuditLogRowID

  While(@@FETCH_STATUS = 0)
  BEGIN
      INSERT INTO AuditLog(AuditLogRowID, AuditColumnID, 
                           NewValue, OldDisplayValue, NewDisplayValue)
        (SELECT @AuditLogRowID,
                [ac].[AuditColumnID], 
                [t0].[UserEnteredValue], 
                [t0].[PreviousDisplayValue],
                [t0].[DisplayValue]
          FROM FMG_PROD.dbo.AuditLog AS [t0]
          INNER JOIN FMG_PROD.dbo.AuditDBColumn AS [t1] 
             ON [t0].[AuditDBColumnID] = [t1].[AuditDBColumnID]
          INNER JOIN FMG_PROD.dbo.AuditDBTable AS [t2] 
             ON [t1].[AuditDBTableID] = [t2].[AuditDBTableID]
          INNER JOIN AuditTable AS [AT] 
             ON [t2].AuditDBTable = [AT].AuditTable
          INNER JOIN AuditColumn AS [AC] 
             ON [AT].AuditTableID = [AC].AuditTableID 
          WHERE     
             ([t0].[AuditBatchID] = @AuditBatchID_logRow)  
             AND ([t0].[AuditOperationID] = @AuditOperationID_logRow)
             AND ([AT].[AuditTableID] = @AuditDBTableID_logRow) 
             AND [AC].AuditColumn = [t1].AuditDBColumn 
             AND (@RowIdentifier_logRow = 
                CASE ISNUMERIC(@RowIdentifier_logRow)
                  WHEN 1 then 
                      CAST ([t0].[RowID] AS VARCHAR(200))
                  ELSE 
                      CAST([t0].[RowGUID] AS VARCHAR(200))
     END))

         FETCH NEXT FROM Crsr_AUDITLOGROW 
           INTO @AuditBatchID_logRow, 
                @AuditOperationID_logRow, 
                @RowIdentifier_logRow, 
                @AuditDBTableID_logRow,
                @AuditLogRowID
END

CLOSE Crsr_AUDITLOGROW
DEALLOCATE Crsr_AUDITLOGROW

1 个答案:

答案 0 :(得分:8)

嗯,你正在思考和编写类似于结构化程序员的代码 - 一个接一个地线性地编程,对程序流程进行最严格的控制。这就是我们(几乎)所有人都被认为是编程的方式。

你需要像SQL人一样思考 - 在 SETS 数据中(不是单行,一次一个)。

避免需要严格控制算法的每一步 - 相反,只需告诉SQL Server WHAT - 不要 HOW 执行每一步!

最后,您将一堆行插入AuditLog表中。为什么你需要一个游标?

 INSERT INTO AuditLog(...list of columns.....)
    SELECT (....list of columns....)
    FROM Table1
    INNER JOIN ..........
    INNER JOIN .........
    WHERE ........

你已经完成了!定义要插入表格中的 - 不要告诉SQL Server如何做到这一点令人厌烦 - 它会非常清楚,谢谢!

马克