当前位置:  开发笔记 > 数据库 > 正文

sql2000在存储过程中循环

如何解决《sql2000在存储过程中循环》经验,为你挑选了2个好方法。

我是SQL的新手,我可以很容易地使用基本语句,但我还没有想出循环.

Foreach(JobHeaderID AS @OldJobHeaderID in dbo.EstimateJobHeader WHERE EstimateID=@OldEstimateID)  
{  
  INSERT EstimateJobHeader (ServiceID,EstimateID) 
  SELECT ServiceID, @NewEstimateID 
  FROM EstimateJobHeader 
  WHERE EstimateID=@OldEstimateID;  

  SELECT @err = @@error 
  IF @err <> 0 
  BEGIN 
    ROLLBACK TRANSACTION 
    SET @RETURN_VALUE = 4 
    RETURN 4 
  END  

  SET @NewJobHeaderID = CAST(SCOPE_IDENTITY() AS INT)  

  SELECT @err = @@error 
  IF @err <> 0 
  BEGIN 
    ROLLBACK TRANSACTION 
    SET @RETURN_VALUE = 3 
    RETURN 3 
  END  

  INSERT EstimateDetail (JobHeaderID, OtherCols) 
  SELECT (@NewJobHeaderID,OtherCols) 
  FROM EstimateDetail 
  WHERE JobHeaderID=@OldJobHeaderID

  SELECT @err = @@error 
  IF @err <> 0 
  BEGIN 
    ROLLBACK TRANSACTION 
    SET @RETURN_VALUE = 3 
    RETURN 3 
  END  

  INSERT EstimateJobDetail (JobHeaderID, OtherCols) 
  SELECT (@NewJobHeaderID, OtherCols) 
  FROM EstimateJobDetail 
  WHERE JobHeaderID=@OldJobHeaderID  

  SELECT @err = @@error 
  IF @err <> 0 
  BEGIN 
    ROLLBACK TRANSACTION 
    SET @RETURN_VALUE = 3 
    RETURN 3 
  END  
}

Joel Coehoor.. 6

您应该避免存储过程中的循环.

Sql是一种声明性语言,而不是您最常使用的命令式语言.您想要对循环执行的任何操作都应该基于集合操作或在客户端代码中完成.当然,有例外,但没有你想象的那么多.

请参阅:
为什么在T-SQL中进行循环如此困难


您询问了如何使用基于集合的方法执行此操作.我会尽我所能,但是你的代码早期存在一个错误,这使我很难确定我正在读它.第一个INSERT语句的条件与FOREACH循环上的条件匹配.所以循环只会运行一次(那里返回一条记录),或者你的插入每次迭代插入几条新记录(是的,插入语句一次可以添加多条记录).如果它添加了几条记录,为什么你只获得最后一次插入创建的标识?

也就是说,我认为我理解它足以向你展示一些东西.看起来你只是在制作估算的副本.您也没有解释@NewEstimateID值的来源.如果有一个父表那么就是这样,但知道它会有所帮助.

/* Where'd @NewEstimateID come from? */
/* If there are several records in EstimateJobHeader with @OldEstimateID,
 *  this will insert one new record for each of them */
INSERT EstimateJobHeader (ServiceID,EstimateID)
     SELECT ServiceID, @NewEstimateID 
     FROM EstimateJobHeader
     WHERE EstimateID= @OldEstimateID

/* Copy EstimateDetail records from old estimate to new estimate */
INSERT EstimateDetail (JobHeaderID, OtherCols) 
    SELECT (new.JobHeaderID,ed.OtherCols) 
    FROM EstimateJobHeader new
    INNER JOIN EstimateJobHeader old ON old.EstimateID= @OldEstimateID 
        AND new.EstimateID= @NewEstimateID AND old.ServiceID=new.ServiceID
    INNER JOIN EstimateDetail ed ON ed.JobHeaderID= old.JobHeaderID

/* Copy EstimateJobDetail records from old estimate to new estimate */
INSERT EstimateJobDetail (JobHeaderID, OtherCols)
    SELECT (new.JobHeaderID,ed.OtherCols) 
    FROM EstimateJobHeader new
    INNER JOIN EstimateJobHeader old ON old.EstimateID= @OldEstimateID 
        AND new.EstimateID= @NewEstimateID AND old.ServiceID=new.ServiceID
    INNER JOIN EstimateJobDetail ejd ON ejd.JobHeaderID= old.JobHeaderID

上面的代码假设ServiceID + EstimateID在EstimateJobHeader表中是唯一的.如果不是这种情况,我需要知道哪些列或列可以唯一地标识表中的行,这样我就可以使用new加入旧记录,并确保关系是1:1.

最后,为简洁起见,省略了错误检查.



1> Joel Coehoor..:

您应该避免存储过程中的循环.

Sql是一种声明性语言,而不是您最常使用的命令式语言.您想要对循环执行的任何操作都应该基于集合操作或在客户端代码中完成.当然,有例外,但没有你想象的那么多.

请参阅:
为什么在T-SQL中进行循环如此困难


您询问了如何使用基于集合的方法执行此操作.我会尽我所能,但是你的代码早期存在一个错误,这使我很难确定我正在读它.第一个INSERT语句的条件与FOREACH循环上的条件匹配.所以循环只会运行一次(那里返回一条记录),或者你的插入每次迭代插入几条新记录(是的,插入语句一次可以添加多条记录).如果它添加了几条记录,为什么你只获得最后一次插入创建的标识?

也就是说,我认为我理解它足以向你展示一些东西.看起来你只是在制作估算的副本.您也没有解释@NewEstimateID值的来源.如果有一个父表那么就是这样,但知道它会有所帮助.

/* Where'd @NewEstimateID come from? */
/* If there are several records in EstimateJobHeader with @OldEstimateID,
 *  this will insert one new record for each of them */
INSERT EstimateJobHeader (ServiceID,EstimateID)
     SELECT ServiceID, @NewEstimateID 
     FROM EstimateJobHeader
     WHERE EstimateID= @OldEstimateID

/* Copy EstimateDetail records from old estimate to new estimate */
INSERT EstimateDetail (JobHeaderID, OtherCols) 
    SELECT (new.JobHeaderID,ed.OtherCols) 
    FROM EstimateJobHeader new
    INNER JOIN EstimateJobHeader old ON old.EstimateID= @OldEstimateID 
        AND new.EstimateID= @NewEstimateID AND old.ServiceID=new.ServiceID
    INNER JOIN EstimateDetail ed ON ed.JobHeaderID= old.JobHeaderID

/* Copy EstimateJobDetail records from old estimate to new estimate */
INSERT EstimateJobDetail (JobHeaderID, OtherCols)
    SELECT (new.JobHeaderID,ed.OtherCols) 
    FROM EstimateJobHeader new
    INNER JOIN EstimateJobHeader old ON old.EstimateID= @OldEstimateID 
        AND new.EstimateID= @NewEstimateID AND old.ServiceID=new.ServiceID
    INNER JOIN EstimateJobDetail ejd ON ejd.JobHeaderID= old.JobHeaderID

上面的代码假设ServiceID + EstimateID在EstimateJobHeader表中是唯一的.如果不是这种情况,我需要知道哪些列或列可以唯一地标识表中的行,这样我就可以使用new加入旧记录,并确保关系是1:1.

最后,为简洁起见,省略了错误检查.



2> casperOne..:

看看WHILE声明:

http://msdn.microsoft.com/en-us/library/aa260676(SQL.80).aspx

但是,根据您要做的事情,可能有一种更好的,基于集合的方式来执行您要执行的操作,并且应该首先考虑这一点.

推荐阅读
黄晓敏3023
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有